Shipping Policy Change Monitor - Free Threshold
Pricing
from $90.00 / 1,000 verified promise-change rows
Shipping Policy Change Monitor - Free Threshold
Track DTC shipping-promise changes daily — free-shipping thresholds, fees and delivery windows with evidence rows. Max $29/run for up to 193 rows — capped, lands clean; monthly total capped at $29. Quiet runs $0.
Pricing
from $90.00 / 1,000 verified promise-change rows
Rating
0.0
(0)
Developer
steadyworks
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a month ago
Last modified
Categories
Security
Limited permissionsShare
Track competitor shipping promises with a daily watch — paste your shop watchlist in, get one verified row per real change (free-shipping threshold, fee, delivery window, returns term) with a was-now pair and an evidence link. The Shipping Policy Change Monitor scrapes shipping-policy data for free, bills only on verified change ($0.15 per verified row, quiet runs $0), and stays capped at $29/month.
Click Try for free — input opens prefilled. Start as-is, check rows, then raise cap.
What it does / What you get
The Shipping Policy Change Monitor watches the shipping-policy, returns-policy, and cart pages you list, once per daily run, and reports only typed, evidence-backed changes — never a guess.
- Free-shipping threshold tracking — catches moves like
$50 → $75with the before/after text on file. - Fee and delivery-window rows — ship fees, delivery-window text, and returns-day terms, each as its own typed row.
- Evidence on every row — each change carries
evidenceUrl,checkedAt, and a fetch-provenance note. - Quiet means quiet — unchanged stores emit zero rows and bill $0; the run summary still shows what was watched.
- Walls are skipped, never guessed — bot-walled, login-walled, and JS-only pages stay quiet instead of producing a fabricated change.
- Spend guards on both ends — a per-run
maxSpendUsdguard plus a $29/month accrual cap with counts-only suppression past the cap (baseline frozen, nothing lost). - Agent-ready output — default-dataset rows plus a matching
OUTPUTrecord in the key-value store for chaining.
Quick start: scrape shipping policies in 5 steps
- Click Try for free (input opens prefilled with a 3-shop demo watchlist — a
$0synthetic first run). - Keep the demo URLs or replace them with 3–10 competitor domains you are allowed to watch (shipping, returns, and cart pages).
- Leave
cadence: "daily"and the caps as-is for the first run. - Click Save & Start, then open the Dataset tab when the run finishes.
- First run lands quiet (0 rows, $0 — boot proven). Add the frozen demo replay or widen the watchlist once the row shape looks right.
Click Try for free — input opens prefilled. Start as-is, check rows, then raise cap.
Input: watchlist API contract
Minimal JSON (required-only — paste this to start):
{"watchId": "shipping-watch-demo-01","competitors": ["shop-a.example.com", "shop-b.example.com", "shop-c.example.com"],"competitorPolicyUrls": ["https://shop-a.example.com/shipping","https://shop-a.example.com/returns","https://shop-a.example.com/cart","https://shop-b.example.com/shipping","https://shop-b.example.com/returns","https://shop-b.example.com/cart","https://shop-c.example.com/shipping","https://shop-c.example.com/returns","https://shop-c.example.com/cart"],"cadence": "daily"}
Full JSON (all defaults — matches the Console prefill byte-for-byte):
{"watchId": "shipping-watch-demo-01","competitors": ["shop-a.example.com", "shop-b.example.com", "shop-c.example.com"],"competitorPolicyUrls": ["https://shop-a.example.com/shipping","https://shop-a.example.com/returns","https://shop-a.example.com/cart","https://shop-b.example.com/shipping","https://shop-b.example.com/returns","https://shop-b.example.com/cart","https://shop-c.example.com/shipping","https://shop-c.example.com/returns","https://shop-c.example.com/cart"],"cadence": "daily","computeCapUsd": 39,"maxSpendUsd": 29,"capMode": "capped","synthetic": true}
| field | type | required | default | units | limits |
|---|---|---|---|---|---|
watchId | string | yes | — (prefill shipping-watch-demo-01) | — | lowercase letters, digits, dashes; max 64 chars; use a fresh value per watch |
competitors | string[] | yes | — | domains | 3–10 domains per run |
competitorPolicyUrls | string[] (url) | yes | — | URLs | 3–30 http(s) URLs: shipping, returns, and cart pages |
cadence | string (enum) | yes | daily | — | only "daily" is accepted; anything else is rejected pre-run with zero spend |
computeCapUsd | number | no | 39 | USD | 0–39; test-window compute bound, separate from the per-row meter |
maxSpendUsd | number | no | 29 | USD | 0.15–29; per-run spend guard — a run that would bill past it stops fail-closed before any charge |
capMode | string (enum) | no | capped | — | capped (default, today's promise verbatim) or complete-input (one manual run processes the whole watchlist; worst case quoted pre-charge, never above $6.00; schedules/tasks always capped) |
synthetic | boolean | no | true | — | marks fixture-scale synthetic input |
seededBaseline | object | no | — | — | fixture replay only: frozen per-store baseline; omit for the honest seed-and-silence boot (0 rows, $0) |
secondRunObservations | array | no | — | — | fixture replay only: frozen second-run observations; omit for the honest boot |
checkedAt | string | no | — | ISO-8601 date-time | optional carried run timestamp; omit for the carried default |
Job-titled one-line recipes: DTC founder threshold watch (3 shops, shipping pages only, maxSpendUsd: 0.15) · agency multi-shop sweep (10 domains, 30 URLs, maxSpendUsd: 5) · holiday-cutoff watch (carrier + big-box date pages, daily cadence) · cap-guarded edge check (2-row cut against the $0.15 floor — stops before any charge) · quiet-rerun proof (byte-identical rerun, 0 rows, $0).
Output: change data rows with evidence
Results land in the default dataset (one summary item per run; switch to the promise-changes view for one-row-per-change) plus the same summary as the OUTPUT record in the default key-value store for agent chaining. Buyer A never sees buyer B's rows — every run gets its own private dataset.
| field | type | description |
|---|---|---|
store | string | watched domain the change was read on |
changeType | string (enum) | threshold · fee · delivery-window · returns |
was / now | string | before/after promise text, verbatim |
evidenceUrl | string (url) | live page the pair was read from |
checkedAt | string (ISO-8601) | when the pair was observed |
fetchPath | string | plain static read or browser-fallback rendered-pass read |
notice | string | human-readable row note |
billable / billableEvent | boolean / string | true / verified-promise-change-row on priced rows |
unitPriceUsd | number | 0.15 per priced row |
rowId / watchId | string | stable row key / scope key |
billedRows / spendUsd | integer / number | run totals for billing-compare |
suppressedRows / capTripped | integer / boolean | counts-only rows past the $29 cap + cap flag |
Real example rows (shortened for viewing — same shops as the input above):
[{"watchId": "shipping-watch-demo-01","rowId": "shipping-watch-demo-01-shop-a-example-com-threshold","store": "shop-a.example.com","changeType": "threshold","was": "Free shipping on orders over $50.","now": "Free shipping on orders over $75.","evidenceUrl": "https://shop-a.example.com/shipping","checkedAt": "2026-09-28T08:00:00Z","fetchPath": "plain","billable": true,"billableEvent": "verified-promise-change-row","unitPriceUsd": 0.15},{"watchId": "shipping-watch-demo-01","rowId": "shipping-watch-demo-01-shop-c-example-com-returns","store": "shop-c.example.com","changeType": "returns","was": "60-day free returns.","now": "30-day free returns.","evidenceUrl": "https://shop-c.example.com/returns","checkedAt": "2026-09-28T08:00:00Z","fetchPath": "plain","billable": true,"billableEvent": "verified-promise-change-row","unitPriceUsd": 0.15}]
Rows shortened for viewing — full items also carry notice, billingNote, and the run-level meter report (billedRows, spendUsd, accruedUsd, suppressedRows, capTripped). Unchanged stores are skipped with zero rows, never a guessed change.
How much will it cost?
from $150.00 / 1,000 verified promise-change rows ($0.15 per row). The billable event is verified-promise-change-row: it fires once per typed was-now change that passes validation and publishes. Quiet runs, jitter, login-walled skips, and seed runs are not billed — empty and failed runs cost $0.
| plan | $/1k verified rows |
|---|---|
| Pay-per-event meter (all plans) | $150.00 |
Tier prices live on the Pricing tab — the Console price is authoritative. The repo manifest (docs/launch/price-manifest.json v1.1.0) is the spec; any mismatch blocks publish.
Worked math (all at $0.15/row):
- First check (1 store, 3 pages): 0 rows quiet → $0.
- Small change day (2 verified rows): 2 × $0.15 → $0.30/run.
- Active month (10 changes): 10 × $0.15 → $1.50/mo.
- Heavy month (100 changes): 100 × $0.15 → $15.00/mo.
- Cap binds at ~193 rows: past $29/mo the run suppresses billable rows counts-only, keeps watching, and freezes the baseline — nothing is lost, the next run re-flags and re-bills.
Cap/floor/quiet: per-run guard maxSpendUsd ($0.15–$29, default $29) stops the run fail-closed before any charge if it would cost more; $29/mo accrual ceiling enforced per watch + calendar month; floor/minimum $0.15 (one row); quiet runs $0; test-window compute bound $39 (separate from the per-row meter). Set Max total charge (ACTOR_MAX_TOTAL_CHARGE_USD) as an extra platform-side ceiling.
Max $29/run for up to 193 units — lands SUCCEEDED at the cap; you pay more only if you turn on [Complete my input] (capMode: "complete-input", one manual run) — worst case computed from your input and quoted in the first log line + OUTPUT before any charge, never above $6.00 (40 rows = 10 stores × 4 typed fields × $0.15). Quotes above $6.00 fall back to capped fail-closed; schedules and task runs always run capped; the monthly $29 room and your Max total charge pin still bind; lift trips land counts-only + SUCCEEDED (lifted-cap-trip).
event:verified-promise-change-row | $/1k 150.00 flat (single meter — tier prices on the Pricing tab) | includes_usage:false | billed_on_empty:false | caps:[maxSpendUsd,monthly-29-scopeBook] | quiet:[actor-start,quiet-runs-$0]
Trial: free first check, no paid plan needed
The standard $5 Apify trial credit ≈ 33 verified rows ($5 ÷ $0.15) — enough to prove the full loop many times over. No paid plan is needed to try.
- Free first check: 1 store (1 domain, up to 3 policy pages), daily cadence —
$0, proves boot plus a quiet read. Before the trial limit is reached, the run reports how many free checks remain and names the paid full-watch upgrade. - Manual checks stop being enough at ~5 stores re-checked daily (about 30 min/day of hand-checking, and changes slip for days) — that is the break size where the paid watch pays for itself.
- Paid upgrade: full watch at
$0.15per verified promise-change row; quiet runs$0; accrual capped at$29/mo.
Click Try for free — input opens prefilled. Start as-is, check rows, then raise cap.
Compatibility: which stores this shipping scraper reads
Works with any server-rendered DTC shipping-policy, returns-policy, or cart page carrying a readable promise (threshold, fee, delivery window, returns term). Verified live:
- Apple — $50 → $75 free-shipping threshold change, Oct 2026 (rendered-pass catch)
- USPS — 2025 → 2026 holiday delivery-window change, Oct 2026 (archived-to-live replay, one step below a live catch)
- Glossier — shipping policy reads cleanly, Oct 2026 (no change found — read proof, not a catch)
- Cotopaxi — shipping policy reads cleanly, Oct 2026 (no change found — read proof, not a catch)
- Both directions in one run — the USPS change was caught while Glossier and Cotopaxi stayed correctly quiet: a catch and a clean read side by side.
Not covered: bot-walled stores, login-walled pages, and pages that never show shipping text in static HTML (plain path) or outside the per-target rendered pass. These stay quiet — never a guessed change.
Store names belong to their owners; no affiliation, endorsement, or sponsorship implied. Not affiliated with Apple, USPS, Glossier, or Cotopaxi.
What people use it for + What it does NOT do
- DTC founder threshold watch — know the morning a rival moves free shipping from $50 to $75.
- Agency multi-shop sweep — one daily run across a client's competitor set, evidence links ready to paste into the report.
- Holiday-cutoff watch — carrier date pages and big-box holiday overlays as the season windows open.
- Fee and returns-term drift — restocking fees, ship-fee edits, and 60-day → 30-day returns cuts.
- Promo-threshold rotation — dated offer pages that rotate tiers into Black Friday and the holidays.
What this Actor does NOT do:
- Does not edit, reorder, or touch your store or anyone else's — read-only, rows out only.
- Does not bypass logins, captchas, or bot walls — walled pages are skipped, never forced.
- Does not guess: no readable promise text means no row, never an inferred change.
- Does not keep memory between runs beyond the watch scope you supply — each run compares what you send it.
Use with schedules / webhooks / API / MCP
Schedules (daily watch): Console → Schedules → New schedule → target this Actor with your watchlist input → repeat daily. Each run checks the list once and bills only on verified change; quiet days cost $0.
Webhooks (alert only when rows > 0): add a run-succeeded webhook and filter on the payload — forward only when billedRows > 0:
{ "event": "ACTOR.RUN.SUCCEEDED", "forwardIf": "billedRows > 0", "then": "post dataset items to Slack/email" }
API (curl): start a run, then poll — call-actor waits ≤45s, so poll get-actor-run or use a webhook, never block:
$curl -X POST "https://api.apify.com/v2/acts/steadyworks~shipping-policy-change-monitor/runs?token=$APIFY_TOKEN" -H "Content-Type: application/json" -d '{"watchId":"my-shop-watch","competitors":["shop-a.example.com"],"competitorPolicyUrls":["https://shop-a.example.com/shipping"],"cadence":"daily"}'
Python one-liner:
run = client.actor("steadyworks/shipping-policy-change-monitor").call(run_input={"watchId": "my-shop-watch", "competitors": ["shop-a.example.com"], "competitorPolicyUrls": ["https://shop-a.example.com/shipping"], "cadence": "daily"})
JavaScript one-liner:
const run = await client.actor("steadyworks/shipping-policy-change-monitor").call({ watchId: "my-shop-watch", competitors: ["shop-a.example.com"], competitorPolicyUrls: ["https://shop-a.example.com/shipping"], cadence: "daily" });
MCP (dispatcher recipe):
{"mcpServers": {"apify": {"command": "npx","args": ["-y", "@apify/mcp-server", "call", "steadyworks/shipping-policy-change-monitor"]}}}
Then call with the minimal input above, poll get-actor-run past 45s, and read rows from the default dataset (promise-changes view) or the OUTPUT key-value record. Chain per-row evidenceUrl into any downstream summarizer.
Troubleshooting
| symptom | cause | fix |
|---|---|---|
| 0 rows on first run | honest seed-and-silence boot (no baseline supplied yet) | expected — proves boot at $0; supply seededBaseline + secondRunObservations for the frozen demo replay, or widen the watchlist |
| 0 rows on later runs | genuinely no change (correct-quiet) | check the run summary (storesWatched, spendUsd: 0); no action — you are billed $0 |
| Run stops before charging | maxSpendUsd pre-flight guard tripped (would-be cost exceeds the per-run cap) | 0 rows, 0 charge by design; raise maxSpendUsd (≤29) or narrow the watchlist |
capTripped: true, counts-only rows | $29/mo accrual ceiling reached | watching continues, baseline frozen, nothing lost — next run re-flags and re-bills |
| Input rejected, no fetch | schema gate (fewer than 3 domains/URLs, bad watchId, non-daily cadence) | fix to 3–10 domains, 3–30 URLs, cadence: "daily"; rejections happen pre-run at $0 |
| Walled store silently absent | bot wall / login wall / JS-only page skipped per policy | expected — never a guessed row; check fetchPath notes; drop or replace the URL |
FAQ + legality
Does this change my store or anyone's data? No — read-only. The Actor fetches public policy pages and writes rows to your own private dataset; it edits nothing, anywhere.
How much will one watch cost? See the worked math above: quiet days $0, each verified change $0.15, worst case $29/mo. A 2-change day is $0.30.
What are the input limits? 3–10 competitor domains and 3–30 policy URLs per run, cadence fixed to daily, per-run guard $0.15–$29 (default $29).
What happens behind login walls or bot walls? The page is skipped and stays quiet — never a guessed row, never a bypass attempt, never billed.
Does it process personal data (GDPR)? No. It reads public shipping/returns/cart policy text only — no accounts, no personal data collected, stored, or sold. Each run's dataset is private to that run's owner.
Is this affiliated with the stores it reads? No. Store names belong to their owners; no affiliation, endorsement, or sponsorship is implied. Monitor only pages you are allowed to watch, and respect each site's Terms of Use and robots directives.
Other Actors you might need
No sibling actors from this publisher yet — this is the only listing. Wrong-fit pointers:
| need | where to look |
|---|---|
| One-off single-page fetch (no watch, no change rows) | Store search → any generic web-scraper actor |
| Full product-catalog scrape (prices, variants, images) | Store search → product/catalog scraper actors |
| Saved runnable configs (smoke, DTC watch, cap edge) | This Actor's Example tasks tab after listing |
Changelog + support
./CHANGELOG.md — 0.1 (2026-10-02): adoption baseline, daily DTC promise watch at $0.15/verified row, $29/mo cap, $0.15 floor, quiet runs $0. Questions: the Store listing's Issues tab.