Give it a list of company domains. Get back what each company changed recently, read from its own sitemap: pages updated in the last 7, 30 and 90 days by section (changelog, pricing, integrations, product, customers, blog, docs, careers), the latest notable URLs, a 0–100 launch score and plain-English reasons to reach out this week.
No monitors to set up first. The dates are already in the sitemap, so the first run shows the last 90 days. Sitemap dates that a build job stamped on every page are caught and never charged.
Run on Apify Store →| status | ok (analyzed, charged) or one of the free statuses listed under Pricing |
|---|---|
| changes | Pages whose lastmod falls in each window, after the noise filter — e.g. 22 / 68 / 166 for 7 / 30 / 90 days |
| bySection | Per section: URLs in the sitemap, pages with a trustworthy date, and changes in the last 7, 30 and 90 days |
| launchScore | 0–100. Pricing, changelog, integration, product and customer pages weigh most; docs and careers weigh little |
| notableUrls | Up to 20 recently changed changelog, pricing, integration, product and customer URLs from the last 90 days, newest first, with their dates |
| pitchReasons | e.g. “16 integration pages updated in the last 30 days (e.g. /integrations/teamretro): expanding their ecosystem; partnership or integration pitch” |
| lastmodReliable, noise | Whether the site’s dates can be trusted, and what the filter took out: same-timestamp batches, sweeps, restamped sections |
| sitemap, reason | Which sitemap files were read and how much of the site they cover; reason says why a row is free or what was excluded from its counts |
Many sites write their build date on every URL, or rewrite hundreds of dates in one batch job. Read those sitemaps naively and a quiet company looks like it changed 3,000 pages last week. Launch Signals checks each site before it counts anything:
Last-Modified day): the domain is lastmod_unreliable and gets no counts.The filter errs toward under-counting: a real launch that touched 200 pages in one deploy is excluded as a batch. For the hand-run version of these checks, see how to find recently updated pages on a website.
Input {"domains": ["linear.app", "intercom.com", "vercel.com", "stripe.com"]}, run on 27 September 2026:
| Domain | status | 30 days | Score | Charged |
| linear.app | ok | 68 | 82 | $0.03 |
|---|---|---|---|---|
| intercom.com | ok | 197 | 45 | $0.03 |
| vercel.com | lastmod_unreliable | none: 94% of recent dates fail the filter | free | |
| stripe.com | no_lastmod | none: the sitemap has no dates | free | |
The run cost $0.06. Intercom changed more pages than Linear, but 194 of its 197 were docs and help-center pages, so it scores 45 to Linear’s 82. The linear.app row, trimmed:
{
"input": "linear.app",
"status": "ok",
"launchScore": 82,
"changes": { "last7d": 22, "last30d": 68, "last90d": 166 },
"bySection": {
"changelog": { "urls": 255, "dated": 162, "last7d": 1, "last30d": 3, "last90d": 9 },
"integrations": { "urls": 325, "dated": 268, "last7d": 3, "last30d": 16, "last90d": 54 },
"customers": { "urls": 43, "dated": 28, "last7d": 0, "last30d": 2, "last90d": 6 },
"docs": { "urls": 203, "dated": 160, "last7d": 17, "last30d": 42, "last90d": 77 }
},
"latestChangeAt": "2026-09-26T12:50:49.000Z",
"notableUrls": [
{ "url": "https://linear.app/integrations/teamretro",
"section": "integrations", "lastmod": "2026-09-26T12:50:49.000Z" },
{ "url": "https://linear.app/changelog/2026-09-24-new-controls-for-linear-coding-agent",
"section": "changelog", "lastmod": "2026-09-25T07:59:41.000Z" }
],
"pitchReasons": [
"3 changelog/release pages updated in the last 30 days (latest: /changelog/2026-09-24-new-controls-for-linear-coding-agent): shipping actively; reference a recent release in outreach",
"16 integration pages updated in the last 30 days (e.g. /integrations/teamretro): expanding their ecosystem; partnership or integration pitch",
"2 customer stories updated in the last 30 days (e.g. /customers/commure): investing in social proof and sales enablement"
],
"reason": "Counts exclude 61 of 227 URLs dated in the last 90 days as machine restamps (1 same-timestamp batch in the last 90 days, largest 10 URLs at 2026-07-23T15:28:23.000Z (over 265s); 2 one-by-one sweeps in the last 90 days, largest 23 blog pages from 2026-07-23T15:02:07.000Z over 80 min)."
}
And the vercel.com row, free:
{
"input": "vercel.com",
"status": "lastmod_unreliable",
"lastmodReliable": false,
"launchScore": null,
"changes": null,
"reason": "5712 of 6055 URLs dated in the last 90 days (94%) don't count as trustworthy changes: 5488 are machine restamps (127 same-timestamp batches in the last 90 days, largest 809 URLs at 2026-08-18T06:10:12.000Z; ...). When over 90% of a site's recent dates don't hold up, the rest can't be trusted either, so no counts are reported. Not charged."
}
launchScore and work the active ones first. Pair with Hiring Signals to see who is also hiring.Limits worth knowing: a sitemap date can’t say what changed on a page or whether it’s new, and pages left out of the sitemap (often pricing) can’t be seen. The crawler identifies itself as SiftsmithBot, obeys robots.txt, and fetches only robots.txt and sitemap files, never the pages themselves.
| Analyzed domain | $0.03 ($30 per 1,000) — charged only when the row comes back status: "ok" |
|---|
A row is ok only when at least 80% of the site’s sitemap files were read, under 25% failed to download (none of them a high-signal file such as a changelog, pricing, product or blog sitemap), at least 5 trustworthy changes remain in the last 90 days, and something changed in the last 30 days: at least one pitch reason, or a changelog, pricing, integration, product or customer page updated in that time.
Free: lastmod_unreliable, no_lastmod, stale_sitemap, too_few_changes, no_notable_changes, partial_coverage, no_sitemap, sitemap_empty, sitemap_fetch_failed, blocked_by_robots, redirected, nxdomain, unreachable, not_public, invalid inputs, errors and duplicates (https://www.linear.app/pricing and linear.app are one domain). Free rows carry changes: null, never zeros. Set a max charge per run and the tool stops cleanly at that limit; any inputs left get a free skipped row.