n8n+DiffHook

n8n + Puppeteer — headless Chrome scraping without the ops

DiffHook drives Puppeteer for you, waits for the DOM to settle, diffs the result against the previous snapshot, and delivers changes to n8n over a signed webhook. No Chromium binary, no Docker image, no restart-on-OOM.

Hosting Puppeteer inside an n8n deployment is a classic footgun: the Chromium binary balloons your image size, workers leak memory after a few hundred runs, and any page change breaks the selector script at 3am. DiffHook pulls the browser into a managed fleet. You describe what to watch once, and n8n sees only the post-render diff — never the browser crashes, never the cold-start latency, never the stealth-plugin version drift.

n8n

The complete n8n + DiffHook hub

See every n8n recipe, template, and pricing tier in one place.

Workflow

Wire Puppeteer-rendered diffs into n8n in 5 steps

The browser runs on our side. n8n only sees changes — no cold starts, no zombie Chromium processes.

01

Expose an n8n webhook

Add a Webhook trigger node to a new or existing n8n workflow, note the production URL. This is the destination DiffHook will POST to when the rendered DOM changes.

02

Pick html_rendered and the Puppeteer engine

Set type to html_rendered and render.engine to puppeteer. Add wait_for_selector or wait_until: networkidle so DiffHook only snapshots after the page has finished loading JS and data.

03

Target the right element with a selector

DiffHook runs the CSS selector against the rendered DOM. Use a tight selector (a specific product card, a pricing row, a status banner) so the diff is focused and n8n only fires on the signal you care about.

04

Create the monitor

POST /v1/monitors with the URL, render config, selector, interval, and a webhook delivery to your n8n URL. DiffHook schedules the Puppeteer runs — you own nothing browser-shaped.

05

React to change in n8n

When the rendered selector output changes, n8n's Webhook node fires with a signed JSON body: previous_value, current_value, url, detected_at. Verify HMAC, then route the diff to the downstream steps.

API example

Puppeteer-rendered monitor, one POST

render.engine picks the browser. Puppeteer is a good default for sites that specifically test for Chrome-family fingerprints.

POST /v1/monitors
POST https://api.diffhook.com/v1/monitors
Authorization: Bearer $DIFFHOOK_API_KEY
Content-Type: application/json

{
  "type": "html_rendered",
  "url": "https://spa.example.com/pricing",
  "render": { "engine": "puppeteer", "wait_for_selector": "[data-ready]" },
  "css_selector": "main .plan",
  "interval_seconds": 600,
  "deliveries": [
    {
      "type": "webhook",
      "url": "https://n8n.yourdomain.com/webhook/spa-pricing"
    }
  ]
}

Importable workflow

Start from a ready-made n8n workflow

Template handles the HMAC check, parses the Puppeteer-rendered HTML with HTML Extract, and pushes structured rows to a Notion database. Edit the destination node to suit.

FAQ

n8n Puppeteer — common questions

Puppeteer vs Playwright — which engine should I pick?
They're interchangeable for ~95% of sites. Pick Puppeteer when the target explicitly tests Chrome features (Chrome DevTools Protocol calls, Chrome-specific browser APIs), or when you've found a page that renders differently under the two. Pick Playwright when you need tighter control over waits or the site works better with Playwright's default browser profile. Switching between them is a one-line change in the monitor config.
Do I need to run my own Chromium anywhere?
No. DiffHook hosts the Chromium fleet, keeps it updated, and recycles workers between runs. You just send the POST. That's the main reason this pattern beats "n8n + Puppeteer node": there's no binary to install, no image to maintain, no crashed-worker alert to triage.
How does DiffHook handle pages that lazy-load content on scroll?
Two options. You can set scroll_to_bottom: true so Puppeteer auto-scrolls the page before snapshotting, or supply a wait_for_selector that only appears once the lazy-loaded content mounts. Both work for infinite-scroll product listings, lazy-loaded changelogs, and intersection-observer widgets.
Can I pass auth cookies into Puppeteer?
Yes. Each monitor has a cookies array and a request_headers map, both stored encrypted. Useful when you want to watch the authenticated view of an app — a dashboard behind login, a tenant-specific SaaS page. Rotate or revoke the credentials from the dashboard at any time.
What's the check cadence on rendered monitors?
Same minimums as static monitors — 60 seconds on paid plans, hourly on free. The browser makes each check more expensive in plan-usage terms, but the dashboard always shows the effective cost per monitor, so there's no cliff.

Related workflows

Also great with DiffHook

Stop shipping Chromium with your n8n image

Managed Puppeteer fleet, HMAC-signed webhooks, 60-second checks, free tier. Ship to production in minutes.