Free forever for hobby projects

Real OTP codes
for your E2E tests

Stop mocking OTPs. Stop wrestling with MailSlurp regex. Get real OTP codes and magic links in one line — from any auth flow, any framework, any CI.

No credit card. Works with Playwright, Cypress, Vitest, Puppeteer.

Playwright
Cypress
Vitest
@otpmagiclink/playwright
Write test
Test runs
Sandbox captures
waitForOtp()
Verified
Sign up with OTP · 1/3

signup.spec.ts

1 |

Browser

yourapp.com/signup

Waiting for test to start…

Sandbox

empty

The problem

Testing OTP flows is a nightmare

Mocking breaks in production

Your CI passes because you hardcoded “123456”. Then a real user hits a bug your test never covered.

MailSlurp is generic + expensive

30 minutes of setup, custom regex, $49/mo — for a job that should be one line.

Real SMS in tests is expensive

Twilio-based test runs add up fast. Carrier delays make tests slow and flaky. Rate limits break CI.

Parallel tests collide

Two testers hit the same inbox. OTP expires before the second one reads it. Test fails. QA rage-refactors.

Developer-first

Test OTP flows in one line

Works with any auth provider. Same SDK for Playwright, Cypress, and Vitest.

Playwright
import { SandboxClient } from '@otpmagiclink/playwright'

const sandbox = new SandboxClient({
  apiKey: process.env.OTP_API_KEY,
})

test('signup with email OTP', async ({ page }) => {
  await page.goto('/signup')
  await page.fill('[name=email]', 'test@yourapp.com')
  await page.click('button[type=submit]')

  const otp = await sandbox.waitForOtp('test@yourapp.com')

  await page.fill('[name=otp]', otp)
  await expect(page).toHaveURL('/dashboard')
})
Cypress
import { SandboxClient } from '@otpmagiclink/cypress'

const sandbox = new SandboxClient({
  apiKey: Cypress.env('OTP_API_KEY'),
})

it('signs up with magic link', () => {
  cy.visit('/signup')
  cy.get('[name=email]').type('test@yourapp.com')
  cy.get('button[type=submit]').click()

  sandbox.waitForMagicLink('test@yourapp.com').then((link) => {
    cy.visit(link)
    cy.url().should('include', '/dashboard')
  })
})

One-line SDK

await sandbox.waitForOtp(email). No inbox setup, no regex parsing, no timeouts.

Instant retrieval

OTPs available in milliseconds. No 30-second email polling. No flaky tests.

Parallel-safe

Run tests in parallel without collision. Each test session gets isolated storage.

Works with any auth

Better Auth, Clerk, Auth.js, Supabase, or custom. Test the flow, not the vendor.

No real SMS costs

Sandbox never sends real emails or SMS. Run thousands of tests without carrier bills.

CI/CD ready

Works out of the box in GitHub Actions, CircleCI, GitLab. Just add your API key.

Works with any auth stack

Better Auth · Clerk · Auth.js · Supabase · Custom

We don't care what auth provider you use. Your app sends the OTP or magic link, we catch it, your test reads it. Same API everywhere.

Simple pricing

Free tier that's actually useful. Paid tiers if you scale.

Free

$0

Forever

  • ✓ Unlimited test runs
  • ✓ Playwright SDK
  • ✓ 1 project
  • ✓ Community support
Get started

Pro

Most popular

$19/mo

For teams and power users

  • ✓ Unlimited test runs
  • ✓ Unlimited projects
  • ✓ CI/CD integration
  • ✓ Email support
Upgrade to Pro

Need more volume or team seats? Get in touch — we'll sort something out.