Docs / Guides

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
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
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
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
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
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
// 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
    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.
← Previous Custom Services Next → Error Handling