DataForSEO to Google Sheets, keyword wins revealed
You find a competitor ranking for everything… but figuring out what they rank for turns into a messy, manual spreadsheet project. Export here, copy there, reformat columns, then repeat it all next week because the data is already stale.
SEO managers feel this when content planning stalls. Agency owners feel it when client “quick wins” turn into late nights. And if you run marketing at a small business, this DataForSEO Sheets automation gives you a clean keyword opportunity table without the constant busywork.
This workflow pulls competitor ranking keywords, enriches them with difficulty, trends, and intent, then writes the results into Google Sheets. You’ll see what it does, what you need, and how to get real outcomes from it.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: DataForSEO to Google Sheets, keyword wins revealed
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n1@{ icon: "mdi:database", form: "rounded", label: "Read Seeds", pos: "b", h: 48 }
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Format Data"]
n3@{ icon: "mdi:cog", form: "rounded", label: "Collect All Results", pos: "b", h: 48 }
n4@{ icon: "mdi:database", form: "rounded", label: "Write to Sheet", pos: "b", h: 48 }
n5@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Over Domains", pos: "b", h: 48 }
n6@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Get Keyword Difficulty"]
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Get Keywords"]
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge"]
n10["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Flatten Data"]
n9 --> n2
n1 --> n5
n2 --> n3
n10 --> n5
n8 --> n7
n8 --> n9
n6 --> n1
n5 --> n4
n5 --> n8
n3 --> n10
n7 --> n9
end
subgraph sg1["Flow 2"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Find n8n's IP"]
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n6 trigger
class n1,n4 database
class n7,n8,n0 api
class n2,n10 code
classDef customIcon fill:none,stroke:none
class n2,n7,n8,n9,n10,n0 customIcon
The Problem: Competitor keywords are locked in messy exports
Most “keyword research” starts with suggestions, not reality. Meanwhile, your competitor already has a proven list of ranking keywords, spread across locations, languages, and SERP types, and it’s sitting behind a few API calls you don’t want to babysit. Doing it manually usually means pulling one export, cleaning it up, then realizing you still need difficulty, intent, trends, and backlink context to decide what’s worth writing. It’s not hard work. It’s draining work, and it steals time from planning content that can actually win.
The friction compounds. Here’s where it breaks down in real life.
- You end up with multiple disconnected exports, so comparing domains turns into spreadsheet gymnastics.
- Difficulty and intent checks become a second project, which means “quick wins” don’t stay quick.
- Manual cleanup invites errors, and one wrong column mapping can skew your whole plan.
- By the time the sheet is ready, the data is already old and you hesitate to repeat the process.
The Solution: DataForSEO competitor keywords enriched in Google Sheets
This n8n workflow turns competitor rankings into a decision-ready table inside Google Sheets. It starts by reading a simple list of domain “seeds” from your input sheet (plus location and language settings), then calls DataForSEO to fetch all the keywords those domains already rank for. Next, it requests bulk keyword difficulty scores, then merges everything into a consistent row format. From there, it enriches the rows with the extra context you actually use to prioritize: trends, intent classification, backlink metrics, and timestamps. Finally, it appends the finished dataset into a dedicated output tab called keywords_opportunities, so your team can sort, filter, and plan without chasing exports.
The workflow begins on a schedule, so the sheet stays fresh without someone remembering. DataForSEO provides rankings and difficulty, then the workflow transforms and flattens the results into one clean table. Google Sheets becomes the “source of truth” you can share with clients or stakeholders.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you track 5 competitor domains and you usually export rankings, then enrich them with difficulty and intent. Even at a conservative 20 minutes per domain for export/cleanup and another 15 minutes per domain to enrich and reformat, that’s about 3 hours each run. With this workflow, you add the 5 domains to the input sheet once, then let the scheduled run populate keywords_opportunities. Your “work” becomes a quick review and filtering session, often 15–20 minutes, not an afternoon.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store seed inputs and results
- DataForSEO API for ranking keywords and difficulty metrics
- DataForSEO credentials (get them from your DataForSEO dashboard; use Basic Auth)
Skill level: Intermediate. You’ll connect accounts, set credentials, and confirm your sheet columns match the workflow expectations.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A scheduled run kicks it off. n8n runs this workflow on a timetable (daily, weekly, or whatever you set), so your keyword opportunities stay current without extra reminders.
Your domain list is pulled from Google Sheets. The workflow reads each row of “seed” domains plus the location and language settings you want to analyze. Then it loops through them in batches, which keeps large pulls from getting chaotic.
DataForSEO data gets fetched and combined. One request retrieves the keywords a domain ranks for, then a follow-up request grabs bulk keyword difficulty scores for those keywords. n8n merges the streams so each keyword row has the important context side by side.
Rows are transformed and written back to your sheet. The workflow formats fields into a consistent structure, aggregates and flattens the data, then appends it into the keywords_opportunities tab where you can filter by difficulty, intent, or trends.
You can easily modify the input columns (like limit or location/language) to focus on a niche market or a specific country. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Schedule Trigger
Set the workflow to run on a recurring monthly schedule using the built-in schedule trigger.
- Add and open Scheduled Run Trigger.
- Set the schedule rule to run monthly by configuring the interval field to months.
- Connect Scheduled Run Trigger to Fetch Seed Entries.
Step 2: Connect Google Sheets
Pull seed domains from a Google Sheet and prepare the destination sheet for results.
- Open Fetch Seed Entries and set Document to
[YOUR_ID]and Sheet to1232412. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Fetch Seed Entries.
- Open Append Results to Sheet and set Operation to
append. - Set Document to
[YOUR_ID]and Sheet to[YOUR_ID]in Append Results to Sheet. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Append Results to Sheet.
⚠️ Common Pitfall: Ensure the destination sheet contains the exact column names mapped in Append Results to Sheet, such as keywords, Search Volume, and Keyword Difficulty.
Step 3: Set Up Keyword Retrieval and Parallel API Calls
Split the seed list into batches, call the keyword API, and run difficulty scoring in parallel.
- Open Iterate Domain List and keep default batch options, then connect it to Pull Site Keywords and Append Results to Sheet.
- In Pull Site Keywords, set URL to
https://api.dataforseo.com/v3/dataforseo_labs/google/keywords_for_site/liveand Method toPOST. - Set JSON Body in Pull Site Keywords to
=[{ "target": "{{ $json.seed }}", "location_name": "{{ $json.location_name }}", "language_name": "{{ $json.language_name }}", "limit": {{ $json.limit }} }]. - Pull Site Keywords outputs to both Retrieve Difficulty Scores and Combine Data Streams in parallel.
- In Retrieve Difficulty Scores, set URL to
https://api.dataforseo.com/v3/dataforseo_labs/google/bulk_keyword_difficulty/liveand Method toPOST. - Set JSON Body in Retrieve Difficulty Scores to
={{ JSON.stringify([ { "keywords": $json.tasks[0].result[0].items.map(i => i.keyword), "location_name": $('Iterate Domain List').item.json.location_name, "language_name": $('Iterate Domain List').item.json.language_name } ]) }}.
⚠️ Common Pitfall: The DataForSEO endpoints require authentication headers—add your API credentials in the Headers section of both Pull Site Keywords and Retrieve Difficulty Scores.
Step 4: Set Up Data Merging and Transformation
Combine the keyword and difficulty streams, then reshape the data into rows for Google Sheets.
- Open Combine Data Streams and set Mode to
combineand Combine By tocombineByPosition. - Connect Retrieve Difficulty Scores to input 2 of Combine Data Streams, and Pull Site Keywords to input 1.
- In Transform Keyword Rows, keep the provided JavaScript Code to map keyword metrics and difficulty into row objects.
- Connect Combine Data Streams to Transform Keyword Rows, then to Aggregate Output Items.
- In Aggregate Output Items, set Aggregate to
aggregateAllItemData. - Open Flatten Aggregated Rows and keep the provided JavaScript Code to output individual row items.
Step 5: Configure Output Mapping to Google Sheets
Map the transformed fields to the destination sheet columns and complete the loop for each batch.
- Connect Flatten Aggregated Rows to Iterate Domain List so the loop continues until all domains are processed.
- In Append Results to Sheet, confirm column mappings such as keywords →
={{ $json.keywords }}and Keyword Difficulty →={{ $json['Keyword Difficulty'] }}. - Verify additional mappings like Search Volume →
={{ $json['Search Volume'] }}and SE Type →={{ $json['SE Type'] }}.
Step 6: Test and Activate Your Workflow
Validate the workflow with a manual run, then enable it for scheduled execution.
- Click Execute Workflow to run Scheduled Run Trigger manually.
- Check that Fetch Seed Entries returns seed data and that Append Results to Sheet appends rows to your Google Sheet.
- Confirm that Pull Site Keywords and Retrieve Difficulty Scores both return valid API responses and merge correctly in Combine Data Streams.
- Once validated, toggle the workflow to Active to enable scheduled runs.
Common Gotchas
- DataForSEO credentials can expire or be rejected if the Basic Auth values are wrong. If things break, check the HTTP Request node credentials and the latest response error message first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 30 minutes if your Sheets and DataForSEO credentials are ready.
No. You’ll mostly connect accounts and confirm the Google Sheets columns match what the workflow expects.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in DataForSEO API costs, which depend on how many keywords you pull per run.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s the whole point. Add more rows to the input Google Sheet with different seed, location_name, and language_name values, then adjust the limit column to control how much data you pull. If you want to reshape the output, the “Transform Keyword Rows” step is where you map fields into the format you prefer. Some teams also rename or extend the output sheet columns to match their content brief template.
Most of the time it’s Basic Auth credentials that are missing or outdated. Update the username/password in the HTTP Request credential inside n8n, then re-run a single seed row to test. If you still see failures, check the DataForSEO dashboard for account limits or blocked requests, and confirm you’re calling the right endpoints for “Keywords For Site” and “Bulk Keyword Difficulty”.
It depends on your n8n plan and your DataForSEO limits, but most teams comfortably run a few domains at a time with a few thousand keywords per run. On n8n Cloud Starter, you are mainly constrained by monthly executions, while self-hosting removes execution limits (your server becomes the bottleneck). If you’re scaling up, reduce the per-domain limit, increase batching, and run it more often instead of pulling everything at once.
Often, yes, because this is not a simple two-step zap. You’re looping through domains, merging multiple API responses, transforming rows, and writing structured output, which is where n8n tends to feel more flexible (and frankly, less expensive at scale if you self-host). Zapier or Make can still work if you only need a small pull for one domain and you don’t care about shaping the dataset. If you want a clean, repeatable research pipeline, n8n is usually the calmer option. Talk to an automation expert if you want help choosing.
Once this is running, competitor keyword research stops being a recurring chore. The workflow handles the repetitive pulls and formatting so you can spend your time choosing the right fights.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.