Cloudflare Workers
notifly uses only the Web API and works natively in Cloudflare Workers. This guide shows a
complete setup with environment variables and wrangler.toml.
Install terminal
copy
npm install @ambersecurityinc/notifly wrangler.toml
Store notification URLs as secrets (not plain vars) so they don't appear in
your source or dashboard logs:
wrangler.toml
copy
name = "my-worker"
compatibility_date = "2025-03-27"
[ vars ]
ENVIRONMENT = "production"
# Secrets — set with: wrangler secret put DISCORD_URL
# DISCORD_URL
# NTFY_URL Set secrets terminal
copy
wrangler secret put DISCORD_URL
# Paste: discord://1234567890/your_webhook_token
wrangler secret put NTFY_URL
# Paste: ntfy://my-alerts Worker code src/index.ts
copy
import { notify } from '@ambersecurityinc/notifly' ;
interface Env {
DISCORD_URL : string ;
NTFY_URL : string ;
}
export default {
async fetch ( request : Request , env : Env ) : Promise < Response > {
const urls = [env. DISCORD_URL , env. NTFY_URL ]. filter (Boolean);
if (urls. length === 0 ) {
return new Response ( 'No notification URLs configured' , { status: 500 });
}
const results = await notify (
{ urls },
{
title: 'Worker Notification' ,
body: 'Something happened in your worker' ,
type: 'info' ,
}
);
const failed = results. filter (( r ) => ! r.success);
if (failed. length > 0 ) {
console. error ( 'Notification failures:' , failed);
}
return Response. json ({ results });
},
async scheduled ( _event : ScheduledEvent , env : Env ) : Promise < void > {
await notify (
{ urls: [env. DISCORD_URL ] },
{ title: 'Cron' , body: 'Scheduled job ran' , type: 'success' }
);
},
} satisfies ExportedHandler < Env >; MailChannels email (free on Workers)
MailChannels is integrated into the Cloudflare Workers network and available for free. Use the
mailto:// scheme with the mailchannels gateway:
typescript
copy
const emailUrl = 'mailto://alerts:mailchannels@' + env. EMAIL_DOMAIN + '?to=' + env. ALERT_EMAIL ;
await notify (
{ urls: [emailUrl] },
{ title: 'Alert' , body: 'Email from a Worker!' , type: 'warning' }
); Queues integration Use Cloudflare Queues to fan out notifications asynchronously:
queue consumer
copy
// Producer: enqueue notification
await env. NOTIFY_QUEUE . send ({
urls: [env. DISCORD_URL , env. NTFY_URL ],
message: { title: 'Event' , body: 'Something happened' },
});
// Consumer: send notifications
export default {
async queue ( batch : MessageBatch < NotifyPayload >, env : Env ) {
for ( const msg of batch.messages) {
await notify (
{ urls: msg.body.urls ?? [env. DISCORD_URL ] },
msg.body.message
);
msg. ack ();
}
},
}; Tips
Never put secrets in wrangler.toml — use wrangler secret put instead.
For local development, create a .dev.vars file (gitignored) with your secrets:
.dev.vars
copy
DISCORD_URL = discord://1234567890/token
NTFY_URL = ntfy://my-alerts
notifly uses fetch() internally, which runs on the Cloudflare edge — no cold
start overhead for network calls.