I build a job site. It reads company career pages, filters hard, and shows you a handful of openings a day. Reasonable product, small footprint.
Then I crawled it properly and found the string JobPosting appears zero times in its entire HTML. On a job site. This is the writeup.
Setup
14 URLs in the sitemap. curl through one proxy, 9 November 2026, scripts and styles stripped before counting words. JSON-LD parsed per page by regex on application/ld+json blocks. Case-insensitive count of "jobposting" on the raw source.
Probes: /jobs, /job/1, /search, /api/jobs. Plus robots.txt and llms.txt.
Numbers
| Page | Words | @type values | JobPosting |
|---|---|---|---|
/ | 427 | WebSite, Organization | 0 |
/pricing | 4 | Answer, FAQPage, Question | 0 |
/about | 447 | AboutPage, Organization, FAQPage, Question | 0 |
/contact | 227 | — | 0 |
/privacy | 1,452 | — | 0 |
/terms | 1,489 | — | 0 |
/guide/ | 169 | Article, CollectionPage, WebSite | 0 |
/guide/h1b-sponsorship-jobs/ | 1,349 | Article, FAQPage, Question | 0 |
/guide/recently-posted-jobs/ | 1,032 | Article, FAQPage, Question | 0 |
/guide/how-many-jobs-should-i-apply-to/ | 1,443 | Article, FAQPage, Question | 0 |
/guide/best-job-aggregator-sites/ | 1,048 | Article, FAQPage, Question | 0 |
/guide/how-long-do-job-postings-stay-up/ | 1,795 | Article, FAQPage, Question | 0 |
/guide/new-grad-jobs-2027/ | 1,142 | Article, FAQPage, Question | 0 |
/guide/limits/ | 2,867 | Article, FAQPage, Question | 0 |
Word total: 14,891. Guide total: 10,676.
Three findings
Question markup, no job markup. Nine pages carry Question and FAQPage. None carries JobPosting. The site is optimized to be quoted by an assistant and not to be listed beside the openings. That's a defensible choice for a product whose pitch is "AI answers cite us" — except the seven guides target exactly the queries where a listing would be the better answer.
No route exists. /job/1 → 404. /search → 404. /jobs → 307 to an unreadable target. robots.txt disallows /api/, and llms.txt confirms postings are read at request time from company boards. Nothing is materialized as a page, so the crawl budget lands on 14 documents and stops.
/pricing is a shell. 4 words after tag stripping, 0 links, from a Next.js server render. It's in the sitemap at priority 0.8 with monthly change frequency, and it declares FAQPage structured data for a Q&A block that isn't in the HTML — the kind of mismatch that gets rich results quietly dropped.
Limits of this audit
No login, so the real inventory behind /api/ is unmeasured. I can say "zero indexable job pages" and nothing stronger.
No Search Console, so I can't tell you what Google does with these 14 URLs — impressions, indexing, rich result eligibility. That data isn't in the crawl.
Conversion from guides to signups: also not measured. No analytics in reach.
Correction
I wrote in an internal note that the job pages were missing because the app is client-rendered. Wrong. The guides are plain HTML, server-side, 1,000+ words, readable without JS. Rendering isn't the failure mode. Absence of a URL is.
Disclosure
jobradarly.com is mine. I'm writing this because the front end looks finished and the crawlable surface is nearly empty, and those two facts sat next to each other for weeks without anyone noticing.
A schema snippet won't fix this. You need a route: one document per posting, datePosted, validThrough, hiringOrganization, canonical to the employer's board. Then the markup has something to describe.
The cost is staleness — a cached posting outlives its own vacancy. That trade-off is the real design decision here, and I haven't settled it.
