Most company websites publish a sitemap that lists every page with the date it last changed. Read it and you can see what a company touched in the last month (new integrations, a changelog entry, a pricing edit) without setting up a monitor first. This page shows how to do that by hand, which dates to distrust, and how to do it for a list of companies in one run.
A sitemap is an XML file, usually at /sitemap.xml and named in /robots.txt, that a site publishes for search engines. Each page gets a <loc> (its URL) and often a <lastmod> (when the site says it last changed). Because the dates are already there, you get the last few months of history on the first look. A page monitor only sees changes made after you add a page to it.
Grouped by section, the dates say what a company is working on:
/integrations/ pages means the company is adding to its ecosystem./pricing page with a recent date is worth opening today.What it can’t tell you: what changed on the page, or whether the page is new or edited. The date says only that the site considers the page changed.
Open https://domain/robots.txt and look for Sitemap: lines. If there are none, try /sitemap.xml and /sitemap_index.xml. If the file you open is a <sitemapindex>, it lists more sitemap files rather than pages; open each <loc> inside it (sitemap-blog.xml, sitemap-product-pages.xml and so on).
For a single sitemap file this prints every dated page, newest first:
curl -sL https://linear.app/sitemap.xml | tr -d '\n' | awk '{gsub(/<url>/,"\n")}1' \
| sed -n 's:.*<loc>\(.*\)</loc>.*<lastmod>\(.*\)</lastmod>.*:\2 \1:p' \
| sort -r | head
On 27 September 2026 it returned:
2026-09-26T12:50:49Z https://linear.app/integrations/teamretro
2026-09-25T20:22:07Z https://linear.app/docs/billing-and-plans
2026-09-25T15:00:20Z https://linear.app/docs/diffs-integrations
2026-09-25T07:59:41Z https://linear.app/changelog/2026-09-24-new-controls-for-linear-coding-agent
2026-09-25T01:42:26Z https://linear.app/docs/jira
2026-09-24T22:36:54Z https://linear.app/enablement/guides/coding-sessions
2026-09-24T22:36:54Z https://linear.app/enablement/guide/coding-sessions
2026-09-24T22:36:54Z https://linear.app/docs/coding-sessions
2026-09-24T16:10:54Z https://linear.app/docs/projects
2026-09-24T15:57:36Z https://linear.app/docs/project-status
A new integration page, a changelog entry and a batch of docs, all in the last three days. The command assumes <lastmod> comes after <loc> inside each <url>, which is the usual order. If you don’t use a terminal, open the sitemap in a browser and search the page for this month’s date, e.g. 2026-09.
# GNU date (Linux); on macOS replace the date part with: date -u -v-30d +%FT%TZ
curl -sL https://linear.app/sitemap.xml | tr -d '\n' | awk '{gsub(/<url>/,"\n")}1' \
| sed -n 's:.*<lastmod>\(.*\)</lastmod>.*:\1:p' \
| awk -v d="$(date -u -d '30 days ago' +%FT%TZ)" '$0 >= d' | wc -l
That compares dates as text, which works for UTC dates ending in Z and for date-only values; a date written with an offset such as +02:00 can be off by a few hours. For linear.app it printed 97. Hold on to that number; the next section is about why it’s too high.
A <lastmod> is whatever the site’s software writes. Plenty of sites write dates that have nothing to do with anyone editing a page. Before you trust a count, run this on the same file. It prints the most common exact timestamps. For vercel.com on 27 September 2026:
curl -sL https://vercel.com/sitemap.xml | tr -d '\n' | awk '{gsub(/<url>/,"\n")}1' \
| sed -n 's:.*<lastmod>\(.*\)</lastmod>.*:\1:p' | sort | uniq -c | sort -rn | head -4
831 2026-06-17T09:43:59.816Z
809 2026-08-18T06:10:12.418Z
539 2026-09-27T11:09:45.522Z
434 2026-08-29T03:11:19.144Z
809 pages don’t get edited on the same millisecond. Those are jobs that rewrote the dates in bulk, and the third line was stamped the same morning we ran the command. Count vercel.com’s last 30 days with the command from step 3 and you get 3,827 of its 7,378 dated URLs, nearly all of them noise. The patterns to look for:
cut -c1-10 before sort | uniq -c to count by day.<lastmod> at all, and pages left out of the sitemap, often the pricing page, don’t show up however you read it.Filtering this by hand for one site is a few minutes of sort | uniq -c. For a list of 50 companies, each with several sitemap files, it’s an afternoon.
Launch Signals reads each company’s sitemap (via robots.txt, following sitemap indexes and gzipped files), throws out the dates that fail the checks above, and returns one row per domain with counts for the last 7, 30 and 90 days split by section. Put domains into Domains on the Apify Store page, or send JSON through the API:
{
"domains": ["linear.app", "intercom.com", "vercel.com",
"figma.com", "stripe.com"]
}
| Input | status | last7d | last30d | last90d | launchScore | Charged |
| linear.app | ok | 22 | 68 | 166 | 82 | $0.03 |
|---|---|---|---|---|---|---|
| intercom.com | ok | 66 | 198 | 392 | 45 | $0.03 |
| vercel.com | lastmod_unreliable | no counts: 94% of the last 90 days’ dates failed the filter | free | |||
| figma.com | partial_coverage | no counts: 20 of 38 sitemap files read before the 50,000-URL cap | free | |||
| stripe.com | no_lastmod | no counts: the sitemap has no dates | free | |||
The run cost $0.06: two domains at $0.03, the other three free. 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 },
"pricing": { "urls": 1, "dated": 0, "last7d": 0, "last30d": 0, "last90d": 0 }
},
"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",
...
],
"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)."
}
What to take from it:
reason says what was taken out./pricing is in its sitemap with no <lastmod>, so a pricing change there can’t be seen this way. Stripe’s sitemap has no dates at all.maxUrlsPerDomain goes up to 200,000.| Build-date stamp | 60% or more of dated pages share one day in the last 90 days (50% if that day is within 2 days of the check or matches the sitemap file’s own Last-Modified): the domain is lastmod_unreliable |
|---|---|
| Same-timestamp batch | 5 or more URLs on the same second, or a chain of 10 or more each within 60 seconds of the last: excluded |
| Bulk-update hour | One clock hour holding at least 20 stamped URLs, or 3% of the site’s dated pages if that’s more (the bar tops out at 100): excluded |
| Stamped sitemap file | A file with 10 or more dated URLs, 70% of them on one recent day: that file is excluded |
| Restamped section | 5 or more dated pages in a section, 80% on one recent day: that section is excluded |
| Rolling section | 20 or more dated pages, 80% “changed” in the last 7 days: excluded (the same test on the whole site makes it lastmod_unreliable) |
| Sweep | 8 or more pages of one section within 60 minutes: excluded |
| Echoes | Category, tag, author and index pages sharing a post’s second count as one change, and never on their own |
| Too little left | Over 90% of the last 90 days’ dates excluded, or fewer than 5 trustworthy changes: no counts, free |
The filter errs toward under-counting. A real launch that touched 200 pages in one deploy is excluded as a batch, and so is a genuine edit to 8 pages of one section inside an hour. The same page in several languages counts once.
Crawling: it identifies itself as SiftsmithBot/0.1 (+https://siftsmith.com), obeys robots.txt, and fetches only robots.txt and sitemap files, never the pages themselves.
| Tool | What it is | Price (official page) |
| Visualping | Page-change monitor: checks the pages you add on a schedule and shows what changed on them | Free for 5 pages checked hourly; Personal $14/month for 10 pages ($10/month billed yearly); Business $140/month for 200 pages ($100/month billed yearly) |
|---|---|---|
| Sitemap URL Extractor (an Apify Actor by another developer) | Lists every URL in a site’s sitemaps with its lastmod, optionally only those changed since a date | $0.50 per 1,000 URLs on Apify’s free plan, from $0.20 per 1,000 on higher tiers |
| Launch Signals | Filtered 7/30/90-day counts by section for a list of domains | $0.03 per domain with a trustworthy result; other rows free; no subscription |
They answer different questions. A monitor like Visualping shows you the actual text or visual change on a page, which a sitemap never will, but only on pages you chose in advance and only from the day you added them. A raw sitemap export gives you every URL and date, which is the right tool for SEO work, and its own page says the lastmod “is reported as the sitemap writes it; it is not independently verified”, so the checks above are up to you. Launch Signals gives one filtered summary per company across all sections, with history from the first run, and nothing about what changed inside a page.
Prices checked 27 September 2026 on Visualping pricing and the Sitemap URL Extractor Store page.
| Analyzed domain | $0.03 ($30 per 1,000), no subscription |
|---|
A domain is charged only when its row comes back status: "ok". That takes all of these:
Every other row is free: lastmod_unreliable, no_lastmod, stale_sitemap, too_few_changes, no_notable_changes, partial_coverage, no_sitemap, sitemap_fetch_failed, blocked_by_robots, redirected, sitemap_empty, nxdomain, unreachable, not_public, invalid input and errors. Free rows have changes: null, never zeros. Duplicates are free too: https://www.linear.app/pricing and linear.app are one domain, and two inputs that read the same sitemaps (notion.so and notion.com) are one site, charged once.
Set a maximum total charge for the run and you’re never charged past it. Once it’s reached, every input left over still gets a row with skipped: true, uncharged.
Only if the pricing page is in the sitemap with a <lastmod>. Search the sitemap for pricing; if it’s there with a date, that’s the site’s own claim of the last change. When a pricing change turns up in a run, it gets its own pitch reason. If you need to know what changed in the prices, use a page monitor on that one page.
No. It means the site considers the page changed. notableUrls are recently changed pages, not necessarily new ones.
At most $6. Sites with no dates, unreliable dates or nothing notable in the last 30 days are free, so it’s usually less; in the five-domain run above, three of five were free.
Yes. Schedule it on Apify, or call it from Clay, Make, Zapier or the API. Using our tools in Clay has the steps, and the MCP page shows how to give it to an AI agent.
Fields, statuses and pricing in one place: the Launch Signals product page.