Slack notifications
Two notifications go to Slack through incoming webhooks. Both are production only. A missing secret turns the notification off; it never blocks a user.
Channels and secrets
Section titled “Channels and secrets”| Channel | Content | Worker | Secret |
|---|---|---|---|
#nowyourlink-signups | One message per new account | api | SLACK_WEBHOOK_SIGNUPS |
#nowyourlink-stats | One message per day at 07:05 UTC | cron | SLACK_WEBHOOK_STATS, CF_ANALYTICS_API_TOKEN |
The helper accepts only https://hooks.slack.com/ URLs. An empty value or a REPLACE_WITH* placeholder is “not configured”.
Sign-up alert
Section titled “Sign-up alert”POST /register calls the hook after it inserts a new pending user. The hook does not fire for a DOI resend, a verified user or the loser of an insert race.
The message contains:
- the UTC time and the environment,
- the email domain (never the local part),
- the country and the locale,
- whether a VAT ID was given (never the VAT ID itself).
The message never contains the company name, the full email or the client IP. The Slack call runs in waitUntil with a 3-second timeout. A Slack failure logs register.slack_notify_failed and does not change the response.
Daily stats
Section titled “Daily stats”The cron lane 5 7 * * * reports yesterday (UTC) against the day before. Each source is independent. A failed or unconfigured source shows “unavailable”, never 0.
| Line | Source | Needs |
|---|---|---|
| Registrations | D1 users.created_at (index users_created_at_idx) | DB binding |
| Cloudflare edge: requests, page views, unique visitors | Zone GraphQL httpRequests1dGroups, all traffic incl. bots | CF_ANALYTICS_API_TOKEN, CF_ZONE_ID |
| First-party page views and top 5 pages | Analytics Engine dataset of the cookieless /api/collect collector | CF_ANALYTICS_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, ANALYTICS_ENGINE_DATASET |
| Notable changes | Any metric with a change of 50 % or more on a base of 10 or more | — |
The sources count different things. The message labels each line and never adds them together. Top pages hide paths with fewer than 2 views.
CF_ZONE_ID is a plain wrangler var (the zone id of nowyourlink.com). CLOUDFLARE_ACCOUNT_ID is a wrangler var that render-wrangler.sh fills from the terraform output cf_account_id.
Set up
Section titled “Set up”- In Slack, create the channels
#nowyourlink-signupsand#nowyourlink-stats. - In a Slack app with Incoming Webhooks, add one webhook per channel.
- In Cloudflare, create a custom API token with Account Analytics: Read and Zone Analytics: Read for
nowyourlink.com. - Put the three values in
.env.production.local. - Push them:
pnpm secrets:put --env production --from .env.production.local --only SLACK_WEBHOOK_SIGNUPS --only SLACK_WEBHOOK_STATS --only CF_ANALYTICS_API_TOKEN --worker api --worker cron --apply. - Deploy through the existing production workflow. Migration 0052 runs in the deploy.
- Sign-up alert: register a test account on production, then look in
#nowyourlink-signups. - Daily stats: the next 07:05 UTC run posts to
#nowyourlink-stats. The worker log showscron.daily_stats.posted, orcron.daily_stats.unconfiguredwhen a secret is missing.