DEV Community

Juanjo
Juanjo

Posted on

Building a Daily Competitor SEO & Tech-Stack Monitor with n8n and a Single API Call

Manually checking a handful of competitor sites every week for SEO regressions or a tech-stack change (a new CMS, a new analytics tool, a new payment provider showing up) doesn't scale, and it's exactly the kind of repetitive check that should just run itself. Here's how to automate it end-to-end with n8n, without writing a scraper.

What "monitoring a competitor" actually requires

Two signals matter most for competitive/SEO monitoring, and they're both annoying to get reliably on your own:

  1. An SEO health score — are they missing meta descriptions, is their robots.txt blocking something it shouldn't, do they have broken canonical tags. This normally means building (or paying for) an auditing tool.
  2. Detected tech stack — did they switch from Shopify to a custom storefront, did they add a new analytics or A/B testing tool, did they start using a new CMS. This normally means either manually inspecting page source/headers, or maintaining your own library of technology fingerprints (script src patterns, meta generator tags, cookie names) — which is a genuinely large, constantly-changing dataset to keep current.

Both of these are solved problems as external APIs, which means the actual automation work is just: read a list of URLs, call an API, compare to yesterday's result, alert on meaningful changes.

The n8n workflow

The shape of this workflow is simple enough to build in an afternoon:

  1. Schedule Trigger — once a day.
  2. Google Sheets (Read) — a Competitors tab with columns url, last_score, last_stack.
  3. Loop over each row.
  4. HTTP Request (SEO audit) and HTTP Request (tech stack) — two parallel calls per URL.
  5. Merge the two responses.
  6. Compare the new score/stack against last_score/last_stack from the sheet — flag if the score dropped more than a threshold (5 points is a reasonable default) or the detected stack changed at all.
  7. IF node — only continue if something actually changed.
  8. Slack/email alert (optional) — post the diff.
  9. Google Sheets (Update) — write the new score/stack back for tomorrow's comparison.

That's the entire scenario. No scraper code, no maintaining your own tech-stack fingerprint database, no parsing HTML yourself.

The part people usually get wrong: comparing state correctly

The easy mistake is comparing the current result to some fixed baseline instead of the previous day's result — which either misses gradual regressions (a score that drops 2 points a day for a week is a 14-point drop nobody notices) or floods you with noise on volatile pages. Reading last_score/last_stack from the same row you're about to update, comparing, then overwriting, is what makes this a rolling day-over-day diff instead of a one-time snapshot.

For the tech-stack comparison specifically, sort the detected technology list before comparing (sorted(stack).join(',') or equivalent) — an API returning the same technologies in a different order between runs will otherwise look like a "change" when nothing actually changed.

Where the API calls come from

For the two HTTP Request nodes above, you need something that returns both an SEO audit score and a tech-stack fingerprint from a single URL — the Web Metadata & Contact Extractor API covers both endpoints (/api/v1/seo-audit and /api/v1/tech-stack) as part of its free tier (1,000 requests/month), which is enough headroom to monitor a meaningful watchlist of competitors daily without hitting limits.

I've published this exact workflow — Google Sheets read, parallel API calls, day-over-day comparison, Slack alert, sheet update — as a ready-to-import n8n template, so you don't have to wire the nodes up from the description above. Drop in your own RapidAPI key and Google Sheet, point it at a Competitors tab with a url column, and it runs daily on its own.

The API itself is open source (MIT license) if you'd rather self-host the extraction logic instead of using the hosted version — the n8n workflow works the same either way, you'd just point the HTTP Request nodes at your own instance.

Top comments (0)