Job search automation · 4 days
UK Job Hunt — Auto-Apply Bot for Amazon Warehouse Roles
A friend in Oldham, UK was applying to Amazon warehouse jobs. Amazon posts new shifts every 20–60 minutes, and they get filled in under 5 minutes. By the time he refreshed the page, the slots were gone. He was checking the site 30+ times a day.
UK Job Hunt — Auto-Apply Bot for Amazon Warehouse Roles
Client: Personal project (open-sourced)
Industry: Job search automation
Timeline: 4 days
Stack: n8n · Puppeteer · Airtable · Gmail API · WATI WhatsApp · Claude
Slug: /case-studies/amazon-jobs-auto-apply
The problem
A friend in Oldham, UK was applying to Amazon warehouse jobs. Amazon posts new shifts every 20–60 minutes, and they get filled in under 5 minutes. By the time he refreshed the page, the slots were gone. He was checking the site 30+ times a day.
What I built
Two workflows that run together:
Workflow A: Monitor (every 20 minutes)
- Puppeteer node renders the Amazon Jobs UK page (it's a JavaScript SPA — plain HTTP requests return an empty shell)
- Code node extracts jobs using three fallback strategies: window state JSON, HTML pattern match, JSON-LD structured data
- Filter node compares against
staticData.seenJobIds(n8n's built-in workflow-level persistence) to find only NEW jobs - IF node sends NEW jobs to WhatsApp via WATI
Workflow B: Auto-apply (every 30 seconds when new jobs detected)
- Login flow: email → 2-second wait → PIN → 3-second wait
- Verification code arrives by email — Gmail polling node grabs it, regex extracts 6 digits
- Submits the apply form with Amazon's session cookie
- Logs to Airtable with status, applied-at timestamp, postal code, radius
- Sends success notification email
Why two workflows? Separation of concerns. The monitor is read-only, runs forever, doesn't break. The applier only fires when there's something to apply for, and if it breaks (auth expired, captcha appears) it doesn't take the monitor down with it.
The hard parts
-
Amazon's site is fully client-rendered. Cheerio doesn't work. Plain
httpRequestreturns<div id="root"></div>. Had to use Puppeteer withwaitUntil: networkidle2. -
Three extraction strategies, in order of reliability:
- First, try
window.__INITIAL_STATE__(works ~60% of the time) - Fallback to HTML regex on job cards (works as long as classNames don't change)
- Last resort: JSON-LD
<script type="application/ld+json">blocks (the most stable but not always present)
- First, try
-
Verification codes expire in 5 minutes. The Gmail polling node had to fire within 30 seconds of login or the code was already stale. Solved by polling every 30 seconds with a tight subject filter.
-
Anti-bot detection. Amazon flags rapid identical requests. Added randomized waits (2s ± 0.5s), rotated user agents, and capped applies at 1 per 30 seconds.
The numbers
- First week: 14 applications submitted, 3 invitations to interview
- Month 1: Friend got hired
- Side effect: Open-sourced both workflow JSONs on my site, ~340 downloads in the first 60 days
Key takeaway
When a site is JS-rendered, just use Puppeteer. Don't fight cheerio for two days. And always build extraction with fallbacks — the site WILL change its DOM next month.
Download Monitor workflow → Download Auto-Apply workflow →