DEV Community

Cover image for Track Errors in Supabase Edge Functions with BugMail
Mark Kaave
Mark Kaave

Posted on • Originally published at bugmail.site

Track Errors in Supabase Edge Functions with BugMail

Supabase Edge Functions run on Deno at the edge, giving you lightning-fast serverless functions. But when they crash in production, you're flying blind — no stack traces, no context, just silent failures.

The challenge ⚠️

Traditional error trackers like Sentry don't officially support Deno. BugMail's core client uses the standard Fetch API, making it naturally compatible with Deno's runtime — no Node.js dependencies required.

Why BugMail Works with Deno
BugMail's core client is built on web standards:

  • Fetch API for HTTP requests (native in Deno, browsers, and Node.js 18+)
  • Zero Node.js dependencies — works anywhere JavaScript runs
  • ESM imports from esm.sh or deno.land

Step 1: Get Your API Key
Sign up at bugmail (free tier available). Copy your API Key and Project ID from the dashboard.

Step 2: Import the Core Client
Import BugMail's core client directly from esm.sh in your Edge Function:

# Install BugMail Core (works with Deno)
# Add to your import_map.json or import directly from esm.sh
import { BugMailCoreClient } from 'https://esm.sh/@bugmail-js/core@latest';
Enter fullscreen mode Exit fullscreen mode

Step 3: Basic Error Tracking Setup

Wrap your function logic in a try/catch block and report errors to BugMail:

// supabase/functions/your-function/index.ts
import { BugMailCoreClient } from 'https://esm.sh/@bugmail-js/core@latest';

// Initialize BugMail client
const bugmail = new BugMailCoreClient({
  baseUrl: 'https://api.bugmail.site',
  apiPath: '/api/sdk/v1/errors',
  apiKey: Deno.env.get('BUGMAIL_API_KEY'),
});

Deno.serve(async (req) => {
  try {
    // Your edge function logic
    const data = await req.json();
    const result = await processData(data);

    return new Response(JSON.stringify(result), {
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    // Report error to BugMail
    await bugmail.captureException(error, {
      headers: { 'x-bugmail-api-key': Deno.env.get('BUGMAIL_API_KEY') },
      payload: {
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
        context: {
          environment: 'production',
          runtime: 'deno-supabase-edge',
          url: req.url,
          method: req.method,
        },
        project_id: Deno.env.get('BUGMAIL_PROJECT_ID'),
        timestamp: new Date().toISOString(),
      },
    });

    return new Response('Internal Server Error', { status: 500 });
  }
});

Enter fullscreen mode Exit fullscreen mode

Step 4: Real-World Example (Payment Webhook)
Here's a complete example tracking errors in a Stripe webhook handler:

// supabase/functions/payment-webhook/index.ts
import { BugMailCoreClient } from 'https://esm.sh/@bugmail-js/core@latest';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

const bugmail = new BugMailCoreClient({
  baseUrl: 'https://api.bugmail.site',
  apiPath: '/api/sdk/v1/errors',
  apiKey: Deno.env.get('BUGMAIL_API_KEY'),
});

const supabase = createClient(
  Deno.env.get('SUPABASE_URL') ?? '',
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
);

Deno.serve(async (req) => {
  try {
    const signature = req.headers.get('stripe-signature');
    if (!signature) throw new Error('Missing stripe signature');

    // Verify webhook signature
    const payload = await req.text();
    const event = verifyWebhook(payload, signature);

    // Process payment
    if (event.type === 'payment_intent.succeeded') {
      const { data, error } = await supabase
        .from('payments')
        .insert({ 
          user_id: event.data.object.metadata.user_id,
          amount: event.data.object.amount,
          status: 'success'
        });

      if (error) throw error;
    }

    return new Response(JSON.stringify({ received: true }), {
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    // Capture with rich context
    await bugmail.captureException(error, {
      headers: { 'x-bugmail-api-key': Deno.env.get('BUGMAIL_API_KEY') },
      payload: {
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
        context: {
          environment: Deno.env.get('ENVIRONMENT') || 'production',
          runtime: 'deno-supabase-edge',
          function: 'payment-webhook',
          url: req.url,
          method: req.method,
          headers: Object.fromEntries(req.headers.entries()),
        },
        project_id: Deno.env.get('BUGMAIL_PROJECT_ID'),
        timestamp: new Date().toISOString(),
      },
    });

    return new Response(
      JSON.stringify({ error: 'Webhook processing failed' }), 
      { status: 500, headers: { 'Content-Type': 'application/json' } }
    );
  }
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Add Environment Variables
In the Supabase Dashboard, navigate to Edge Functions → Secrets and add:

# Supabase Dashboard > Edge Functions > Secrets
# Add these environment variables:

BUGMAIL_API_KEY=your_api_key_here
BUGMAIL_PROJECT_ID=your_project_id_here
ENVIRONMENT=production
Enter fullscreen mode Exit fullscreen mode

You're Done!

Now when your Edge Function throws an error, you'll receive an instant email with the stack trace, request context, and environment details. No complex dashboards, just instant alerts.

Top comments (0)