CheckDisposable Emailcheckdisposable.email
← All guidesSvelteKit guide · TypeScript

Block disposable email signups in SvelteKit

Add the check inside a `+page.server.ts` action. SvelteKit forms post directly to actions, so this is the natural place — no separate API route needed.

The code

// src/routes/signup/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
import { CDE_KEY } from '$env/static/private';
import type { Actions } from './$types';

async function isDisposable(email: string) {
  const r = await fetch(
    `https://api.checkdisposable.email/v1/check?email=${encodeURIComponent(email)}`,
    { headers: { Authorization: `Bearer ${CDE_KEY}` } }
  );
  if (!r.ok) return false;
  return (await r.json()).is_disposable === true;
}

export const actions: Actions = {
  default: async ({ request }) => {
    const form = await request.formData();
    const email = String(form.get('email') ?? '');

    if (await isDisposable(email)) {
      return fail(400, { email, error: 'Please use a real email address.' });
    }

    // ...create user, set session cookie
    throw redirect(303, '/dashboard');
  },
};

Notes

Why $env/static/private
SvelteKit splits env vars into public (`PUBLIC_*`) and private. Importing from `$env/static/private` makes it impossible to accidentally ship the key to the client.
Form errors with use:enhance
In `+page.svelte`, use `<form method="post" use:enhance>` and read `form?.error` from `$page` to render the message inline without a full page reload.
Pair with Lucia / Auth.js
If you use Lucia or Auth.js (sveltekit-auth), put the disposable check in the same action before calling their createUser — both libraries are agnostic to validation order.

Get a free API key

500 checks/month, no credit card. No credit card. 30 seconds.

Sign up free →