@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 +98 -33
- package/dist/nodes/SeRanking/SeRanking.node.js +15 -2
- package/dist/nodes/SeRanking/dataApi/descriptions/SerpClassicDescription.d.ts +3 -0
- package/dist/nodes/SeRanking/dataApi/descriptions/SerpClassicDescription.js +231 -0
- package/dist/nodes/SeRanking/dataApi/operations/BacklinksOperations.js +1 -1
- package/dist/nodes/SeRanking/dataApi/operations/DomainAnalysisOperations.js +1 -1
- package/dist/nodes/SeRanking/dataApi/operations/SerpClassicOperations.d.ts +2 -0
- package/dist/nodes/SeRanking/dataApi/operations/SerpClassicOperations.js +127 -0
- package/dist/nodes/SeRanking/seranking.svg +6 -4
- package/dist/nodes/SeRanking/utils/apiRequest.js +1 -13
- package/package.json +9 -3
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
274
|
+
Two comprehensive workflows for monitoring AI visibility and identifying content opportunities.
|
|
262
275
|
|
|
263
|
-
**
|
|
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
|
-
**
|
|
285
|
+
**Workflow 2: Competitor Topic Gap Analysis**
|
|
271
286
|
|
|
272
|
-
|
|
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
|
|
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/
|
|
317
|
+
📂 [View Full Guide & Download Workflow →](./Usage-Examples/SERP-Classic)
|
|
313
318
|
|
|
314
319
|
---
|
|
315
320
|
|
|
316
|
-
### 📊 Example
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
✅ **
|
|
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
|
-
│ │ │
|
|
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
|
-
│ │
|
|
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
|
-
│
|
|
769
|
-
│
|
|
770
|
-
│
|
|
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
|
-
|
|
29
|
-
|
|
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,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
|
-
|
|
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
|
-
|
|
10
|
+
const method = 'GET';
|
|
11
11
|
switch (operation) {
|
|
12
12
|
case 'getOverviewDb': {
|
|
13
13
|
const domain = this.getNodeParameter('domain', index);
|
|
@@ -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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
59
|
+
"typescript": "^5.9.3"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"n8n-workflow": "*"
|
|
57
63
|
},
|
|
58
64
|
"engines": {
|
|
59
65
|
"node": ">=18.0.0"
|