> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shopsniffer.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Background workflows & cron

The Cloudflare Workflows and cron schedules that power daily store monitoring, auto-publishing, and snapshot cleanup.

## Overview

ShopSniffer runs four scheduled background workflows on Cloudflare Workflows, orchestrated by `wrangler.jsonc` cron triggers. This page is the reference for **when** each workflow fires, **what** it does, and **what retention policies** apply to the data it produces.

If you're a user of monitoring, most of what happens here is invisible — daily scans Just Work. This page exists for developers integrating with the data.

## Cron schedule

| Schedule (UTC) | Cron expression | Workflow | Purpose |
| --- | --- | --- | --- |
| Daily 12:00 | `0 12 * * *` | `MonitorShopsWorkflow` | Rescan all tracked stores |
| Weekly Mon 10:00 | `0 10 * * 1` | `AutoPublishBlogWorkflow` | Auto-generate blog posts |
| Daily 14:00 | `0 14 * * *` | `AutoPublishReportsWorkflow` | Publish reports ≥30 days old as SEO content |
| Weekly Sun 03:00 | `0 3 * * SUN` | `CleanupSnapshotsWorkflow` | Delete old snapshots per retention policy |

All times are UTC and configured in [`wrangler.jsonc`](https://github.com/anthropics) under `triggers.crons`.

## `MonitorShopsWorkflow` Stable

**Fires:** Daily at 12:00 UTC.

Picks up every tracked store (across all users), groups them by effective scan frequency, and kicks off a `ScrapeShopWorkflow` for each one that's due. Results:

- A new completed job per store
- A snapshot row in the `jobs` table
- Diff computation vs the previous snapshot → rows in `shop_changes`
- Inventory deltas (sales vs restocks) → rows in `inventory_events`
- A new `changelog` entry per job
- Webhook deliveries and email notifications for any subscribers

### Effective frequency

Each user picks their own scan frequency per store via `PATCH /api/store-detail/:slug/frequency`. The workflow uses the **most aggressive** frequency across all subscribers to that store — if any user wants `daily`, everyone tracking that store gets daily updates.

| User preference | Scanned when |
| --- | --- |
| `daily` | Every 12:00 UTC |
| `weekly` | Every Monday 12:00 UTC |
| `biweekly` | Every other Monday 12:00 UTC |

The "effective frequency" is recomputed every time any subscriber changes theirs. If the last daily subscriber downgrades to weekly, the store immediately drops to weekly cadence on the next cron tick.

## `AutoPublishBlogWorkflow` Internal

**Fires:** Weekly Monday at 10:00 UTC.

Generates a weekly blog post about a trending or recently-analyzed store and publishes it to the public blog at `https://shopsniffer.com/blog`. Admin-only — not configurable by users.

## `AutoPublishReportsWorkflow` Internal

**Fires:** Daily at 14:00 UTC.

Scans for completed reports older than 30 days that haven't been auto-published yet, and promotes them to public SEO content under `https://shopsniffer.com/stores/:slug`. This is how the public store directory gets populated.

**Privacy note**

Jobs you create while signed in are owned by your user ID, but the report data itself may be auto-published as public SEO content after 30 days. If you don't want a report you generated to appear in the public directory, delete it before the 30-day mark. This doesn't apply to stores you track for monitoring — those keep their per-user scoping.

## `CleanupSnapshotsWorkflow` Internal

**Fires:** Weekly Sunday at 03:00 UTC.

Enforces retention on historical snapshot data:

- **Job records** — kept indefinitely; only metadata rows, very small
- **Product/collection/page items** (`job_items`, `shop_items`) — kept indefinitely so diffs always have a baseline
- **R2 export files** (CSV, JSON) — kept for **90 days** per job; older files are deleted to control R2 storage costs
- **Screenshots** — kept for **90 days** per job
- **Inventory snapshots** — kept for **180 days** (needed for velocity calculations)

After cleanup, the job record itself still exists — only the heavy downloadable artifacts are removed. The report API will return a 410 Gone if you try to fetch a pruned file.

## What fires in what order

**Daily 12:00 UTC — monitoring**

`MonitorShopsWorkflow` kicks off a `ScrapeShopWorkflow` for every due tracked store. Downstream: new snapshots, diff computation, webhooks, email notifications.
  **Daily 14:00 UTC — public promotion**

`AutoPublishReportsWorkflow` promotes 30-day-old reports to the public directory.
  **Weekly Mon 10:00 UTC — blog generation**

`AutoPublishBlogWorkflow` publishes a new blog post highlighting recent stores or trends.
  **Weekly Sun 03:00 UTC — cleanup**

`CleanupSnapshotsWorkflow` deletes expired R2 files and screenshots per retention policy.

## Observability

All workflows emit structured logs to Cloudflare Workers Logs. Failed runs are tracked in the admin dashboard (admin-only).

For end-user status, check:

- `GET /api/store-detail/:slug` → `summary.latest_job.created_at` shows when the last scan ran
- `GET /api/changelog/:jobId` → diffs for any individual job
- `GET /api/store-detail/:slug/analytics` → 365-day daily-changes heatmap

## Next steps

**[Monitoring API](/api/monitoring)**

Query snapshot history, changes, and inventory events.
  **[Monitor prices guide](/guides/monitor-prices)**

End-to-end example using webhooks and the changelog API.
  **[Store monitoring](/monitoring)**

Conceptual overview.
  **[Webhooks](/webhooks)**

Delivery semantics for monitoring notifications.