@seranking/n8n-nodes-seranking 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,7 +58,7 @@ npm install n8n -g
58
58
  **Option A: From .tgz file**
59
59
 
60
60
  ```bash
61
- npm install -g n8n-nodes-seranking-1.2.0.tgz
61
+ npm install -g seranking-n8n-nodes-seranking-1.3.0.tgz
62
62
  ```
63
63
 
64
64
  **Option B: From GitHub**
@@ -122,17 +122,23 @@ docker run -it --rm \
122
122
 
123
123
  ### Updating
124
124
 
125
+ **From npm:**
126
+
127
+ ```bash
128
+ npm update @seranking/n8n-nodes-seranking
129
+ ```
130
+
125
131
  **From .tgz:**
126
132
 
127
133
  ```bash
128
- npm uninstall -g n8n-nodes-seranking
129
- npm install -g n8n-nodes-seranking-NEW-VERSION.tgz
134
+ npm uninstall -g seranking-n8n-nodes-seranking
135
+ npm install -g seranking-n8n-nodes-seranking-NEW-VERSION.tgz
130
136
  ```
131
137
 
132
138
  **From GitHub:**
133
139
 
134
140
  ```bash
135
- npm update -g n8n-nodes-seranking
141
+ npm install -g git+https://github.com/seranking/n8n-nodes-seranking.git
136
142
  ```
137
143
 
138
144
  **From source:**
@@ -174,7 +180,7 @@ The node will automatically test your credentials by making a test request to th
174
180
 
175
181
  ## Operations
176
182
 
177
- This node provides access to 5 SE Ranking resources with 54 total operations:
183
+ This node provides access to 6 SE Ranking resources with 59 total operations:
178
184
 
179
185
  ### AI Search (4 operations)
180
186
 
@@ -247,6 +253,13 @@ This node provides access to 5 SE Ranking resources with 54 total operations:
247
253
  - Recheck Standard Audit - Re-run HTML audit
248
254
  - Recheck Advanced Audit - Re-run JS audit
249
255
 
256
+ ### SERP Classic (5 operations)
257
+
258
+ - Add Tasks - Create SERP tasks for keywords (up to 1,000 per request)
259
+ - Get Results - Get standard SERP results for a task
260
+ - List Tasks - List recent SERP tasks (last 24 hours)
261
+ - Get Advanced Results - Retrieve detailed SERP results with all features
262
+ - Get Locations - Get available location IDs for SERP queries
250
263
 
251
264
  ## Usage Examples
252
265
 
@@ -256,30 +269,22 @@ Ready-to-use workflows demonstrating real-world applications of the SE Ranking n
256
269
 
257
270
  ### 🤖 Example 1: AI Search Visibility Tracker
258
271
 
259
- **Track your brand's presence across ChatGPT, Perplexity, and Gemini**
272
+ **Track your brand's presence and competitive gaps across ChatGPT, Perplexity, and Gemini**
260
273
 
261
- Monitor how often your brand appears in AI-powered search engines with automated historical tracking.
274
+ Two comprehensive workflows for monitoring AI visibility and identifying content opportunities.
262
275
 
263
- **What You'll Get:**
276
+ **Workflow 1: AI Search Visibility Tracker**
277
+
278
+ Monitor how often your brand appears in AI-powered search engines with automated historical tracking.
264
279
 
265
280
  - Link presence count across multiple AI engines
266
281
  - Average position tracking in AI citations
267
282
  - AI opportunity traffic estimates
268
283
  - Period-over-period comparison metrics
269
284
 
270
- **Best For:** Marketing teams tracking AI SEO performance, Brand managers monitoring AI visibility
285
+ **Workflow 2: Competitor Topic Gap Analysis**
271
286
 
272
- 📂 [View Full Guide & Download Workflow →](./Usage-Examples/AI-Search)
273
-
274
- ---
275
-
276
- ### 🎯 Example 2: Competitor Topic Gap Analysis
277
-
278
- **Identify content opportunities by analyzing where competitors outrank you in AI search and traditional SEO**
279
-
280
- Comprehensive competitive analysis combining AI visibility gaps with traditional SEO keyword gaps.
281
-
282
- **What You'll Get:**
287
+ Identify content opportunities by analyzing where competitors outrank you in AI search and traditional SEO.
283
288
 
284
289
  - AI visibility gaps across ChatGPT, Perplexity, and Gemini
285
290
  - Keyword gaps with search volume and difficulty
@@ -287,13 +292,13 @@ Comprehensive competitive analysis combining AI visibility gaps with traditional
287
292
  - Prioritized opportunities with HIGH/MEDIUM/LOW scoring
288
293
  - Actionable recommendations for each gap
289
294
 
290
- **Best For:** Content strategists planning editorial calendars, SEO teams doing competitive intelligence
295
+ **Best For:** Marketing teams tracking AI SEO performance, Content strategists planning editorial calendars, SEO teams doing competitive intelligence
291
296
 
292
297
  📂 [View Full Guide & Download Workflow →](./Usage-Examples/AI-Search)
293
298
 
294
299
  ---
295
300
 
296
- ### 🔗 Example 3: Backlinks Monitoring & Analysis
301
+ ### 🔗 Example 2: Backlinks Monitoring & Analysis
297
302
 
298
303
  **Track new/lost backlinks, monitor domain authority, and analyze anchor text distribution**
299
304
 
@@ -309,11 +314,11 @@ Automatically monitor backlink portfolio health with daily tracking and alerts f
309
314
 
310
315
  **Best For:** SEO agencies managing client backlink portfolios, In-house SEO teams tracking link-building campaigns
311
316
 
312
- 📂 [View Full Guide & Download Workflow →](./Usage-Examples/Backlinks)
317
+ 📂 [View Full Guide & Download Workflow →](./Usage-Examples/SERP-Classic)
313
318
 
314
319
  ---
315
320
 
316
- ### 📊 Example 4: Domain Analysis Data Processor
321
+ ### 📊 Example 3: Domain Analysis Data Processor
317
322
 
318
323
  **Transform SE Ranking API data into structured Google Sheets reports**
319
324
 
@@ -333,7 +338,7 @@ Automatically process and organize domain analysis data with intelligent type de
333
338
 
334
339
  ---
335
340
 
336
- ### 🔍 Example 5: Keyword Research Automation
341
+ ### 🔍 Example 4: Keyword Research Automation
337
342
 
338
343
  **Automate comprehensive keyword research with trend analysis**
339
344
 
@@ -352,7 +357,7 @@ Build an automated keyword intelligence pipeline with historical tracking and SE
352
357
 
353
358
  ---
354
359
 
355
- ### 🔧 Example 6: Website Audit Automation
360
+ ### 🔧 Example 5: Website Audit Automation
356
361
 
357
362
  **Automatically crawl sites, detect issues, and generate reports**
358
363
 
@@ -371,6 +376,26 @@ Schedule regular technical SEO audits and get alerts when critical issues are de
371
376
 
372
377
  ---
373
378
 
379
+ ### 📍 Example 6: SERP Classic Tracking
380
+
381
+ **Track keyword rankings and analyze SERP features across search engines**
382
+
383
+ Monitor keyword positions, SERP features, and competitor visibility with automated rank tracking.
384
+
385
+ **What You'll Get:**
386
+
387
+ - Keyword position tracking across multiple locations
388
+ - SERP features analysis (featured snippets, local pack, etc.)
389
+ - Competitor ranking visibility
390
+ - Device-specific rankings (desktop, mobile, tablet)
391
+ - Historical rank tracking
392
+
393
+ **Best For:** SEO teams tracking keyword performance, Local businesses monitoring location-based rankings, Agencies managing multi-client SERP tracking
394
+
395
+ 📂 [View Full Guide & Download Workflow →](./Usage-Examples/SERP-Classic)
396
+
397
+ ---
398
+
374
399
  ### 🚀 Quick Start
375
400
 
376
401
  1. **Browse** the example that matches your use case
@@ -392,6 +417,7 @@ This node implements the following SE Ranking APIs:
392
417
  - [Domain Analysis API](https://seranking.com/api/data/domain-analysis/)
393
418
  - [Keyword Research API](https://seranking.com/api/data/keyword-research/)
394
419
  - [Website Audit API](https://seranking.com/api/data/website-audit/)
420
+ - [SERP API](https://seranking.com/api/data/serp/)
395
421
 
396
422
  For detailed API specifications, visit [SE Ranking API Documentation](https://seranking.com/api.html).
397
423
 
@@ -399,7 +425,27 @@ For detailed API specifications, visit [SE Ranking API Documentation](https://se
399
425
 
400
426
  ## Version History
401
427
 
402
- ### v1.2.3 (Current)
428
+ ### v1.3.0 (Current)
429
+
430
+ - ✅ Complete AI Search resource (4 operations)
431
+ - ✅ Complete Backlinks resource (25 operations)
432
+ - ✅ Enhanced Domain Analysis resource (8 operations - added History, Comparison, Paid Ads)
433
+ - ✅ Complete Keyword Research resource (5 operations)
434
+ - ✅ Complete Website Audit resource (14 operations)
435
+ - ✅ **NEW: Complete SERP Classic resource (5 operations)**
436
+ - ✅ **Total: 59 operations across 6 resources**
437
+ - ✅ Comprehensive error handling with detailed messages
438
+ - ✅ Full TypeScript support
439
+ - ✅ Input validation (domains, sources, dates)
440
+ - ✅ Pagination support (offset/limit)
441
+ - ✅ Advanced filtering options
442
+ - ✅ Multi-keyword support (up to 1,000 keywords for SERP tasks)
443
+ - ✅ Backlink export and bulk operations
444
+ - ✅ Website audit creation and management
445
+ - ✅ **NEW: SERP rank tracking and analysis**
446
+ - ✅ **NEW: Multi-location SERP data retrieval**
447
+
448
+ ### v1.2.3
403
449
 
404
450
  - ✅ Complete AI Search resource (4 operations)
405
451
  - ✅ **NEW: Complete Backlinks resource (25 operations)**
@@ -433,18 +479,30 @@ For detailed API specifications, visit [SE Ranking API Documentation](https://se
433
479
 
434
480
  ## Features
435
481
 
436
- ✅ **54 Operations** - Comprehensive coverage across 5 major resources
482
+ ✅ **59 Operations** - Comprehensive coverage across 6 major resources
483
+
437
484
  ✅ **Type Safety** - Full TypeScript implementation with strict typing
485
+
438
486
  ✅ **Error Handling** - Detailed error messages with troubleshooting hints
487
+
439
488
  ✅ **Pagination** - Efficient handling of large datasets
489
+
440
490
  ✅ **Advanced Filtering** - Volume, position, CPC, difficulty filters
491
+
441
492
  ✅ **Validation** - Input validation for domains, country codes, and parameters
493
+
442
494
  ✅ **Authentication** - Automatic credential management and testing
495
+
443
496
  ✅ **Rate Limiting** - Built-in rate limit handling with retry logic
497
+
444
498
  ✅ **Batch Operations** - Support for multiple keywords/domains
499
+
445
500
  ✅ **Backlink Monitoring** - Complete backlink analysis and tracking
501
+
446
502
  ✅ **Website Auditing** - Technical SEO audits with issue detection
447
503
 
504
+ ✅ **SERP Tracking** - Keyword ranking and SERP features analysis
505
+
448
506
  ---
449
507
 
450
508
  ## Limitations
@@ -711,13 +769,15 @@ n8n-nodes-seranking/
711
769
  │ │ │ ├── BacklinksOperations.ts # Backlinks operations logic
712
770
  │ │ │ ├── DomainAnalysisOperations.ts # Domain Analysis operations logic
713
771
  │ │ │ ├── KeywordResearchOperations.ts # Keyword Research operations logic
714
- │ │ │ └── WebsiteAuditOperations.ts # Website Audit operations logic
772
+ │ │ │ ├── WebsiteAuditOperations.ts # Website Audit operations logic
773
+ │ │ │ └── SerpClassicOperations.ts # SERP Classic operations logic
715
774
  │ │ └── descriptions/
716
775
  │ │ ├── AiSearchDescription.ts # AI Search UI definitions
717
776
  │ │ ├── BacklinksDescription.ts # Backlinks UI definitions
718
777
  │ │ ├── DomainAnalysisDescription.ts # Domain Analysis UI definitions
719
778
  │ │ ├── KeywordResearchDescription.ts # Keyword Research UI definitions
720
- │ │ └── WebsiteAuditDescription.ts # Website Audit UI definitions
779
+ │ │ ├── WebsiteAuditDescription.ts # Website Audit UI definitions
780
+ │ │ └── SerpClassicDescription.ts # SERP Classic UI definitions
721
781
  │ └── utils/
722
782
  │ ├── validators.ts # Input validators
723
783
  │ └── apiRequest.ts # API request handler
@@ -765,9 +825,14 @@ n8n-nodes-seranking/
765
825
  │ │ ├── Get_Longtail_Keywords.jpg # Screenshot: Longtail Keywords
766
826
  │ │ └── README.md # Keyword Research workflow documentation
767
827
  │ │
768
- └── Website-Audit/
769
- ├── Website-Audit-Technical-SEO-Monitor.json # Website audit workflow
770
- └── README.md # Website Audit workflow documentation
828
+ ├── Website-Audit/
829
+ ├── Website-Audit-Technical-SEO-Monitor.json # Website audit workflow
830
+ └── README.md # Website Audit workflow documentation
831
+ │ │
832
+ │ └── SERP-Classic/
833
+ │ ├── Gelato-Small-Towns-Amsterdam-Area.json # SERP tracking workflow
834
+ │ ├── Gelato Small Towns Amsterdam Area.xlsx # Workflow results
835
+ │ └── README.md # SERP Classic workflow documentation
771
836
 
772
837
  ├── package.json
773
838
  ├── package-lock.json
@@ -7,11 +7,13 @@ const DomainAnalysisDescription_1 = require("./dataApi/descriptions/DomainAnalys
7
7
  const KeywordResearchDescription_1 = require("./dataApi/descriptions/KeywordResearchDescription");
8
8
  const BacklinksDescription_1 = require("./dataApi/descriptions/BacklinksDescription");
9
9
  const WebsiteAuditDescription_1 = require("./dataApi/descriptions/WebsiteAuditDescription");
10
+ const SerpClassicDescription_1 = require("./dataApi/descriptions/SerpClassicDescription");
10
11
  const AiSearchOperations_1 = require("./dataApi/operations/AiSearchOperations");
11
12
  const DomainAnalysisOperations_1 = require("./dataApi/operations/DomainAnalysisOperations");
12
13
  const KeywordResearchOperations_1 = require("./dataApi/operations/KeywordResearchOperations");
13
14
  const BacklinksOperations_1 = require("./dataApi/operations/BacklinksOperations");
14
15
  const WebsiteAuditOperations_1 = require("./dataApi/operations/WebsiteAuditOperations");
16
+ const SerpClassicOperations_1 = require("./dataApi/operations/SerpClassicOperations");
15
17
  class SeRanking {
16
18
  constructor() {
17
19
  this.description = {
@@ -25,8 +27,9 @@ class SeRanking {
25
27
  defaults: {
26
28
  name: 'SE Ranking',
27
29
  },
28
- inputs: ['main'],
29
- outputs: ['main'],
30
+ usableAsTool: true,
31
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
32
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
30
33
  credentials: [
31
34
  {
32
35
  name: 'seRankingApi',
@@ -60,6 +63,11 @@ class SeRanking {
60
63
  value: 'keywordResearch',
61
64
  description: 'Keyword metrics, volume, CPC, and related keywords',
62
65
  },
66
+ {
67
+ name: 'SERP Classic',
68
+ value: 'serpClassic',
69
+ description: 'SERP tracking and results retrieval',
70
+ },
63
71
  {
64
72
  name: 'Website Audit',
65
73
  value: 'websiteAudit',
@@ -76,6 +84,8 @@ class SeRanking {
76
84
  ...DomainAnalysisDescription_1.domainAnalysisFields,
77
85
  ...KeywordResearchDescription_1.keywordResearchOperations,
78
86
  ...KeywordResearchDescription_1.keywordResearchFields,
87
+ ...SerpClassicDescription_1.serpClassicOperations,
88
+ ...SerpClassicDescription_1.serpClassicFields,
79
89
  ...WebsiteAuditDescription_1.websiteAuditOperations,
80
90
  ...WebsiteAuditDescription_1.websiteAuditFields,
81
91
  ],
@@ -101,6 +111,9 @@ class SeRanking {
101
111
  case 'keywordResearch':
102
112
  responseData = await KeywordResearchOperations_1.KeywordResearchOperations.call(this, i);
103
113
  break;
114
+ case 'serpClassic':
115
+ responseData = await SerpClassicOperations_1.SerpClassicOperations.call(this, i);
116
+ break;
104
117
  case 'websiteAudit':
105
118
  responseData = await WebsiteAuditOperations_1.WebsiteAuditOperations.call(this, i);
106
119
  break;
@@ -0,0 +1,3 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const serpClassicOperations: INodeProperties[];
3
+ export declare const serpClassicFields: INodeProperties[];
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serpClassicFields = exports.serpClassicOperations = void 0;
4
+ exports.serpClassicOperations = [
5
+ {
6
+ displayName: 'Operation',
7
+ name: 'operation',
8
+ type: 'options',
9
+ noDataExpression: true,
10
+ displayOptions: {
11
+ show: {
12
+ resource: ['serpClassic'],
13
+ },
14
+ },
15
+ options: [
16
+ {
17
+ name: 'Add Tasks',
18
+ value: 'addTasks',
19
+ description: 'Create SERP tasks for keywords (returns task IDs)',
20
+ action: 'Add SERP tasks',
21
+ },
22
+ {
23
+ name: 'Get Results (standard)',
24
+ value: 'getResults',
25
+ description: 'Get status or standard SERP results for a task',
26
+ action: 'Get SERP results',
27
+ },
28
+ {
29
+ name: 'List Tasks',
30
+ value: 'listTasks',
31
+ description: 'List recent SERP tasks (last 24 hours)',
32
+ action: 'List SERP tasks',
33
+ },
34
+ {
35
+ name: 'Get Advanced Results',
36
+ value: 'getAdvancedResults',
37
+ description: 'Retrieve advanced (detailed) SERP results',
38
+ action: 'Get advanced SERP results',
39
+ },
40
+ {
41
+ name: 'Get Locations',
42
+ value: 'getLocations',
43
+ description: 'Get available location IDs for SERP queries',
44
+ action: 'Get SERP locations',
45
+ },
46
+ ],
47
+ default: 'addTasks',
48
+ },
49
+ ];
50
+ exports.serpClassicFields = [
51
+ {
52
+ displayName: 'Search Engine',
53
+ name: 'searchEngine',
54
+ type: 'string',
55
+ required: true,
56
+ displayOptions: {
57
+ show: {
58
+ resource: ['serpClassic'],
59
+ operation: ['addTasks'],
60
+ },
61
+ },
62
+ default: 'google',
63
+ placeholder: 'google',
64
+ description: 'Search engine name (e.g., google, bing). See "Supported Engine IDs by Country" in docs — classic uses engine names like "google".',
65
+ },
66
+ {
67
+ displayName: 'Device',
68
+ name: 'device',
69
+ type: 'options',
70
+ required: true,
71
+ displayOptions: {
72
+ show: {
73
+ resource: ['serpClassic'],
74
+ operation: ['addTasks'],
75
+ },
76
+ },
77
+ options: [
78
+ { name: 'Desktop', value: 'desktop' },
79
+ { name: 'Mobile', value: 'mobile' },
80
+ { name: 'Tablet', value: 'tablet' },
81
+ ],
82
+ default: 'desktop',
83
+ description: 'Search device type (desktop, mobile, tablet).',
84
+ },
85
+ {
86
+ displayName: 'Language Code',
87
+ name: 'languageCode',
88
+ type: 'string',
89
+ required: true,
90
+ displayOptions: {
91
+ show: {
92
+ resource: ['serpClassic'],
93
+ operation: ['addTasks'],
94
+ },
95
+ },
96
+ default: 'en',
97
+ placeholder: 'en',
98
+ description: 'Language code for the search results (e.g., en, fr).',
99
+ },
100
+ {
101
+ displayName: 'Location ID',
102
+ name: 'locationId',
103
+ type: 'number',
104
+ required: true,
105
+ displayOptions: {
106
+ show: {
107
+ resource: ['serpClassic'],
108
+ operation: ['addTasks'],
109
+ },
110
+ },
111
+ default: 0,
112
+ placeholder: '31808',
113
+ description: 'Location identifier (integer) — retrieve IDs from the Get Locations endpoint.',
114
+ },
115
+ {
116
+ displayName: 'Keywords',
117
+ name: 'keywords',
118
+ type: 'string',
119
+ typeOptions: {
120
+ rows: 6,
121
+ },
122
+ required: true,
123
+ displayOptions: {
124
+ show: {
125
+ resource: ['serpClassic'],
126
+ operation: ['addTasks'],
127
+ },
128
+ },
129
+ default: '',
130
+ placeholder: 'avocado\ninterstellar',
131
+ description: 'Keywords — one per line or comma-separated. Max 1,000 keywords; each ≤ 255 chars.',
132
+ },
133
+ {
134
+ displayName: 'Optional: Tag',
135
+ name: 'tag',
136
+ type: 'string',
137
+ required: false,
138
+ displayOptions: {
139
+ show: {
140
+ resource: ['serpClassic'],
141
+ operation: ['addTasks'],
142
+ },
143
+ },
144
+ default: '',
145
+ placeholder: 'campaign-1',
146
+ description: 'Optional: tag to group tasks.',
147
+ },
148
+ {
149
+ displayName: 'Task ID',
150
+ name: 'taskId',
151
+ type: 'string',
152
+ required: true,
153
+ displayOptions: {
154
+ show: {
155
+ resource: ['serpClassic'],
156
+ operation: ['getResults'],
157
+ },
158
+ },
159
+ default: '',
160
+ placeholder: '14',
161
+ description: 'Task ID returned by Add Tasks. Example: 14',
162
+ },
163
+ {
164
+ displayName: 'List Filters',
165
+ name: 'listFilters',
166
+ type: 'collection',
167
+ placeholder: 'Add Filter',
168
+ default: {},
169
+ displayOptions: {
170
+ show: {
171
+ resource: ['serpClassic'],
172
+ operation: ['listTasks'],
173
+ },
174
+ },
175
+ options: [
176
+ {
177
+ displayName: 'Limit',
178
+ name: 'limit',
179
+ type: 'number',
180
+ default: 100,
181
+ description: 'Max tasks to return (UI-level).',
182
+ typeOptions: { minValue: 1, maxValue: 1000 },
183
+ },
184
+ ],
185
+ },
186
+ {
187
+ displayName: 'Task ID',
188
+ name: 'taskId',
189
+ type: 'string',
190
+ required: true,
191
+ displayOptions: {
192
+ show: {
193
+ resource: ['serpClassic'],
194
+ operation: ['getAdvancedResults'],
195
+ },
196
+ },
197
+ default: '',
198
+ placeholder: '14',
199
+ description: 'Task ID to fetch advanced results for. The advanced results endpoint expects a single task_id parameter.',
200
+ },
201
+ {
202
+ displayName: 'Country Code',
203
+ name: 'countryCode',
204
+ type: 'string',
205
+ required: false,
206
+ displayOptions: {
207
+ show: {
208
+ resource: ['serpClassic'],
209
+ operation: ['getLocations'],
210
+ },
211
+ },
212
+ default: '',
213
+ placeholder: 'US',
214
+ description: 'Filter by country code (optional).',
215
+ },
216
+ {
217
+ displayName: 'Query (city / name)',
218
+ name: 'q',
219
+ type: 'string',
220
+ required: false,
221
+ displayOptions: {
222
+ show: {
223
+ resource: ['serpClassic'],
224
+ operation: ['getLocations'],
225
+ },
226
+ },
227
+ default: '',
228
+ placeholder: 'New York',
229
+ description: 'Partial match parameter for location name (optional).',
230
+ },
231
+ ];
@@ -15,7 +15,7 @@ async function BacklinksOperations(index) {
15
15
  const operation = this.getNodeParameter('operation', index);
16
16
  let endpoint = '';
17
17
  const params = {};
18
- let method = 'GET';
18
+ const method = 'GET';
19
19
  switch (operation) {
20
20
  case 'getSummary': {
21
21
  const target = this.getNodeParameter('target', index);
@@ -7,7 +7,7 @@ async function DomainAnalysisOperations(index) {
7
7
  const operation = this.getNodeParameter('operation', index);
8
8
  let endpoint = '';
9
9
  const params = {};
10
- let method = 'GET';
10
+ const method = 'GET';
11
11
  switch (operation) {
12
12
  case 'getOverviewDb': {
13
13
  const domain = this.getNodeParameter('domain', index);
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ export declare function SerpClassicOperations(this: IExecuteFunctions, index: number): Promise<any>;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SerpClassicOperations = SerpClassicOperations;
4
+ const apiRequest_1 = require("../../utils/apiRequest");
5
+ function parseKeywords(input) {
6
+ if (!input || input.trim() === '') {
7
+ throw new Error('Keywords cannot be empty');
8
+ }
9
+ const keywords = input
10
+ .split(/[,\n]/)
11
+ .map((k) => k.trim())
12
+ .filter((k) => k.length > 0);
13
+ if (keywords.length === 0)
14
+ throw new Error('Provide at least one keyword');
15
+ if (keywords.length > 1000)
16
+ throw new Error('Maximum 1000 keywords per request');
17
+ const tooLong = keywords.find((k) => k.length > 255);
18
+ if (tooLong)
19
+ throw new Error('Each keyword must be 255 characters or fewer');
20
+ return keywords;
21
+ }
22
+ function parseTaskIds(input) {
23
+ if (!input || input.trim() === '')
24
+ throw new Error('Task ID(s) required');
25
+ const items = input
26
+ .split(/[,\n]/)
27
+ .map((i) => i.trim())
28
+ .filter((i) => i.length > 0);
29
+ if (items.length === 0)
30
+ throw new Error('Provide at least one task ID');
31
+ return items;
32
+ }
33
+ async function SerpClassicOperations(index) {
34
+ const operation = this.getNodeParameter('operation', index);
35
+ let method = 'GET';
36
+ let endpoint = '';
37
+ const params = {};
38
+ const body = {};
39
+ switch (operation) {
40
+ case 'addTasks': {
41
+ method = 'POST';
42
+ endpoint = '/serp/classic/tasks';
43
+ const searchEngine = this.getNodeParameter('searchEngine', index);
44
+ const device = this.getNodeParameter('device', index);
45
+ const languageCode = this.getNodeParameter('languageCode', index);
46
+ const locationId = this.getNodeParameter('locationId', index);
47
+ const keywordsInput = this.getNodeParameter('keywords', index);
48
+ const tag = this.getNodeParameter('tag', index, '');
49
+ const keywords = parseKeywords(keywordsInput);
50
+ body.search_engine = searchEngine;
51
+ body.device = device;
52
+ body.language_code = languageCode;
53
+ if (typeof locationId !== 'number' || Number.isNaN(locationId)) {
54
+ throw new Error('locationId must be a valid integer');
55
+ }
56
+ body.location_id = Math.floor(locationId);
57
+ body.query = keywords;
58
+ if (tag && tag.trim() !== '')
59
+ body.tag = tag;
60
+ const response = await apiRequest_1.apiRequest.call(this, method, endpoint, body, params, index);
61
+ if (Array.isArray(response)) {
62
+ return response.map((id) => ({ task_id: id }));
63
+ }
64
+ return response;
65
+ }
66
+ case 'getResults': {
67
+ endpoint = '/serp/classic/tasks';
68
+ method = 'GET';
69
+ const taskId = this.getNodeParameter('taskId', index);
70
+ if (!taskId)
71
+ throw new Error('taskId is required');
72
+ params.task_id = taskId;
73
+ const response = await apiRequest_1.apiRequest.call(this, method, endpoint, {}, params, index);
74
+ if (response && response.status === 'processing') {
75
+ return { status: 'processing', raw: response };
76
+ }
77
+ return response;
78
+ }
79
+ case 'listTasks': {
80
+ endpoint = '/serp/classic/tasks';
81
+ method = 'GET';
82
+ const filters = this.getNodeParameter('listFilters', index, {});
83
+ if (filters.limit)
84
+ params.limit = filters.limit;
85
+ const response = await apiRequest_1.apiRequest.call(this, method, endpoint, {}, params, index);
86
+ return response;
87
+ }
88
+ case 'getAdvancedResults': {
89
+ endpoint = '/serp/classic/tasks/results_advanced';
90
+ method = 'GET';
91
+ const taskIdInput = this.getNodeParameter('taskId', index);
92
+ const taskIds = parseTaskIds(taskIdInput);
93
+ const aggregated = [];
94
+ for (const tid of taskIds) {
95
+ const localParams = { task_id: tid };
96
+ const resp = await apiRequest_1.apiRequest.call(this, method, endpoint, {}, localParams, index);
97
+ if (resp && resp.status === 'processing') {
98
+ aggregated.push({ task_id: tid, status: 'processing' });
99
+ continue;
100
+ }
101
+ if (resp && resp.request_metadata) {
102
+ aggregated.push({ task_id: tid, ...resp });
103
+ }
104
+ else {
105
+ aggregated.push({ task_id: tid, raw: resp });
106
+ }
107
+ }
108
+ return aggregated;
109
+ }
110
+ case 'getLocations': {
111
+ endpoint = '/serp/classic/locations';
112
+ method = 'GET';
113
+ const countryCode = this.getNodeParameter('countryCode', index, '');
114
+ const q = this.getNodeParameter('q', index, '');
115
+ if (countryCode && countryCode.trim() !== '')
116
+ params.country_code = countryCode;
117
+ if (q && q.trim() !== '')
118
+ params.q = q;
119
+ const response = await apiRequest_1.apiRequest.call(this, method, endpoint, {}, params, index);
120
+ if (response && response.data)
121
+ return response.data;
122
+ return response;
123
+ }
124
+ default:
125
+ throw new Error(`Unknown operation: ${operation}`);
126
+ }
127
+ }
@@ -1,4 +1,6 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
2
- <rect width="100" height="100" rx="15" fill="#4A90E2"/>
3
- <text x="50" y="60" font-family="Arial, sans-serif" font-size="48" font-weight="bold" fill="white" text-anchor="middle">SE</text>
4
- </svg>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="100" height="100">
3
+ <path d="M0 0 C33 0 66 0 100 0 C100 33 100 66 100 100 C67 100 34 100 0 100 C0 67 0 34 0 0 Z " fill="#123AF8" transform="translate(0,0)"/>
4
+ <path d="M0 0 C2.32849974 2.32849974 1.88976398 6.58005112 2.02441406 9.70385742 C1.7575027 17.04998613 -2.54423971 20.81482648 -7.66821289 25.60620117 C-13.12621684 30.43860935 -16.46675285 32.25875633 -23.953125 32.1953125 C-24.61334656 32.1924826 -25.27356812 32.18965271 -25.95379639 32.18673706 C-28.05271897 32.17558415 -30.15120742 32.15048946 -32.25 32.125 C-33.67707715 32.11496384 -35.10416102 32.1058391 -36.53125 32.09765625 C-40.02097328 32.07566111 -43.51044423 32.04116536 -47 32 C-41.76636873 25.76129422 -36.35356926 19.69382768 -30.74511719 13.79077148 C-29.66705845 12.64074469 -28.60462624 11.47586294 -27.55859375 10.29663086 C-19.11519234 0.80706239 -12.74587141 -2.12034308 0 0 Z " fill="#F9FAFE" transform="translate(65,15)"/>
5
+ <path d="M0 0 C1.02150398 0.00636726 1.02150398 0.00636726 2.06364441 0.01286316 C4.22383334 0.02956265 6.38306517 0.06719563 8.54296875 0.10546875 C10.01365833 0.12052701 11.48436264 0.13421341 12.95507812 0.14648438 C16.54718232 0.17943661 20.13873201 0.23115702 23.73046875 0.29296875 C19.55764529 5.26870293 15.21519448 9.95601662 10.6171875 14.5390625 C9.96216751 15.19503922 9.30714752 15.85101593 8.63227844 16.52687073 C7.2612068 17.89861777 5.88889202 19.26912335 4.51538086 20.63842773 C2.40295774 22.74544132 0.29599267 24.85780901 -1.81054688 26.97070312 C-3.14681443 28.3063108 -4.48339166 29.64160874 -5.8203125 30.9765625 C-6.76865715 31.9279435 -6.76865715 31.9279435 -7.73616028 32.89854431 C-12.15454881 37.29296875 -12.15454881 37.29296875 -13.26953125 37.29296875 C-13.76453125 29.86796875 -13.76453125 29.86796875 -14.26953125 22.29296875 C-21.19953125 21.79796875 -21.19953125 21.79796875 -28.26953125 21.29296875 C-26.62453816 18.00298258 -25.65587716 16.42392127 -23.1875 13.9453125 C-22.58486328 13.34009766 -21.98222656 12.73488281 -21.36132812 12.11132812 C-20.73291016 11.49064453 -20.10449219 10.86996094 -19.45703125 10.23046875 C-18.84021484 9.60591797 -18.22339844 8.98136719 -17.58789062 8.33789062 C-16.98138672 7.73396484 -16.37488281 7.13003906 -15.75 6.5078125 C-14.92858521 5.68978149 -14.92858521 5.68978149 -14.09057617 4.85522461 C-9.40938514 0.83927858 -6.19087176 -0.07643052 0 0 Z " fill="#F6F7FE" transform="translate(58.26953125,47.70703125)"/>
6
+ </svg>
@@ -30,9 +30,6 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
30
30
  baseUrl = 'https://api.seranking.com/v1';
31
31
  }
32
32
  options.url = `${baseUrl}${endpoint}`;
33
- options.headers = {
34
- 'Authorization': `Token ${credentials.apiToken}`,
35
- };
36
33
  options.json = true;
37
34
  }
38
35
  if (Object.keys(query).length > 0) {
@@ -79,7 +76,7 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
79
76
  }
80
77
  }
81
78
  try {
82
- const response = await this.helpers.httpRequest(options);
79
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'seRankingApi', options);
83
80
  return response;
84
81
  }
85
82
  catch (error) {
@@ -126,15 +123,6 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
126
123
  else {
127
124
  errorMessage = (errorData === null || errorData === void 0 ? void 0 : errorData.message) || (errorData === null || errorData === void 0 ? void 0 : errorData.error) || error.message || 'Request failed';
128
125
  }
129
- console.error('SE Ranking API Error:', {
130
- status: statusCode,
131
- message: errorMessage,
132
- url: options.url,
133
- method: options.method,
134
- params: options.qs,
135
- itemIndex,
136
- errorData,
137
- });
138
126
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `SE Ranking API Error: ${errorMessage}`, {
139
127
  itemIndex,
140
128
  description: errorDescription,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seranking/n8n-nodes-seranking",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "n8n connector for SE Ranking API - AI Search, Backlinks, Domain Analysis, Keyword Research, and Website Audit",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/seranking/n8n-nodes-seranking",
@@ -18,6 +18,7 @@
18
18
  ],
19
19
  "keywords": [
20
20
  "n8n",
21
+ "n8n-community-nodes-package",
21
22
  "n8n-community-node-package",
22
23
  "n8n-nodes-seranking",
23
24
  "seranking",
@@ -26,9 +27,11 @@
26
27
  "backlinks",
27
28
  "domain-analysis",
28
29
  "ai-search",
30
+ "serp-task",
29
31
  "website-audit"
30
32
  ],
31
33
  "n8n": {
34
+ "n8nNodesApiVersion": 1,
32
35
  "nodes": [
33
36
  "dist/nodes/SeRanking/SeRanking.node.js"
34
37
  ],
@@ -50,10 +53,13 @@
50
53
  "@typescript-eslint/eslint-plugin": "^5.59.0",
51
54
  "@typescript-eslint/parser": "^5.59.0",
52
55
  "eslint": "^8.40.0",
53
- "eslint-plugin-n8n-nodes-base": "^1.12.0",
56
+ "eslint-plugin-n8n-nodes-base": "^1.16.4",
54
57
  "n8n-workflow": "^1.17.0",
55
58
  "prettier": "^2.8.8",
56
- "typescript": "^5.0.4"
59
+ "typescript": "^5.9.3"
60
+ },
61
+ "peerDependencies": {
62
+ "n8n-workflow": "*"
57
63
  },
58
64
  "engines": {
59
65
  "node": ">=18.0.0"