---
title: "Automate MFA Testing with Playwright — Tutorial, Code & Best Practices"
description: "Automate SMS-based MFA in Playwright tests with the GetMyMFA API. TypeScript setup, a getMfaCode helper, the full test and E2E best practices."
url: "https://get.mymfa.io/blog/playwright-e2e-mfa"
canonical: "https://get.mymfa.io/blog/playwright-e2e-mfa"
markdown: "https://get.mymfa.io/blog/playwright-e2e-mfa.md"
author: "Jonathan Bernales"
author_url: "https://get.mymfa.io/about#jonathan-bernales"
publisher: "GetMyMFA"
date_published: "2025-08-04"
date_modified: "2025-08-04"
category: "Automation"
tags:
  - "Playwright"
  - "Multi-Factor Authentication"
  - "E2E Test Automation"
hub: "https://get.mymfa.io/features/test-automation"
plans: "Pro, Enterprise"
---

# Automate MFA Testing with Playwright — Tutorial, Code & Best Practices

*By Jonathan Bernales, 2025-08-04. Canonical: https://get.mymfa.io/blog/playwright-e2e-mfa*

> **TL;DR** To automate MFA testing with Playwright, use GetMyMFA's API to fetch SMS verification codes during your E2E test. After the login step triggers a 2FA prompt, call the /v1/{phoneId}/mfa/latest endpoint, extract the mfaCode field, and fill it into the verification input using Playwright's page.getByRole locator.

## 🚀 Introduction & Context

**How to automate E2E tests with MFA enforced** is a common questions when working on test automation. When applications implement **Multi-Factor Authentication for security**, traditional test automation approaches break down, forcing teams to either disable MFA in test environments ([which is a bad idea](https://get.mymfa.io/blog/test-automation-limits)) or going back to manual testing or even not testing MFA flows!. This guide aimes to demonstrate how to **automate end-to-end tests with MFA enabled** thanks to GetMyMFA features. Everything below relies on the [GetMyMFA MFA test automation API](https://get.mymfa.io/features/test-automation), available on the Pro and Enterprise plans; the same pattern is covered for [Cypress](https://get.mymfa.io/blog/cypress-e2e-mfa) and [Selenium](https://get.mymfa.io/blog/selenium-e2e-mfa).

This hands-on guide shows how to automate an end-to-end login secured by **SMS-based Multi-Factor Authentication**, using **Playwright** and the **GetMyMFA** API. You can adapt the same pattern to any other critical flow like financial transactions or sensitive approvals.

Testing Multi-Factor Authentication workflows is a challenge for QA teams. As we explored in our article on [overcoming MFA test automation challenges](https://get.mymfa.io/blog/test-automation-limits), traditional approaches often involve **disabling MFA in test environments** or manually handling verification codes, both of which **compromise test reliability and security validation**. This tutorial will show a **production-ready approach** that maintains security while enabling comprehensive automation.

#### 🎯 What we'll build

In this tutorial, we'll create a **complete Playwright test suite** that automatically handles SMS-based MFA authentication. You'll learn to set up a TypeScript project, integrate with GetMyMFA's API, and build a robust test that can **fetch verification codes programmatically** and complete the entire login flow without manual intervention. By the end, you'll have a **production-ready testing solution** that you can adapt for your own applications. *Complete source code is available for download at the end of this article.*

## 🔄 Overview: How the flow works

The end-to-end flow below mirrors a **real user experience** and avoids **insecure test-only shortcuts**:

1. **Start sign-in.** Your test framework launches a login attempt against the demo app.
2. **App sends SMS.** The app sends an MFA code by SMS to a **GetMyMFA virtual number**.
3. **Code exposed via API.** GetMyMFA exposes the SMS securely via API.
4. **Fetch the code.** Your test retrieves the latest code from the API.
5. **Submit the code.** The test injects it into the form and completes authentication.

![Macro process: Playwright triggers login, app sends SMS, GetMyMFA API returns code, test submits MFA](https://get.mymfa.io/_next/static/immutable/media/1_macro-flow.2m3elu1utr-xc.png)

*Note: In this demo, the actual SMS send (step 2) is skipped to avoid cost; the rest remains **fully automated**.*

## 🛠️ Tutorial: Set up Playwright + GetMyMFA

#### 1️⃣ Initialize a Playwright (TypeScript) project

Start by creating a new Playwright project with **TypeScript support**:

```bash
npm init playwright@latest
```

Choose **TypeScript**, confirm tests in the `tests` folder, skip GitHub Actions if you like, and **install Playwright browsers** when prompted.

![Playwright project creation CLI](https://get.mymfa.io/_next/static/immutable/media/2_playwright-creation.225bwr7knw-vc.png)

Your project structure should look like this:

![Playwright project structure](https://get.mymfa.io/_next/static/immutable/media/3_project-structure.1wkt-auiuick9.png)

#### 2️⃣ Create a GetMyMFA test account + API key

Visit [get.mymfa.io](https://get.mymfa.io) and select *Sign Up*. The **Trial option** gives you a **temporary virtual number with API access**. Then open **API Configuration** to create an API key — **store it securely**.

![GetMyMFA dashboard - API configuration](https://get.mymfa.io/_next/static/immutable/media/4_gmm_image.1gmei2jjuqny4.png)

#### 3️⃣ Get your virtual phone number ID

Add your key as a header, `x-api-key`, and call:

```http
GET https://programmatic-api.client.get.mymfa.io/v1/phone-numbers
```

The response includes `phoneId`. To **fetch the most recent code**:

```http
GET https://programmatic-api.client.get.mymfa.io/v1/<YOUR_PHONE_ID>/mfa/latest
```

The **MFA code** is in `mfaCode`.

![Postman call to list phone numbers](https://get.mymfa.io/_next/static/immutable/media/5_postman1.3yiael2czr3-j.png)

If you are curious about how the MFA code is returned, you can run the **second API call through postman**:

![Postman call to get latest MFA code](https://get.mymfa.io/_next/static/immutable/media/6_postman2.0rlpcivt-4if1.png)

#### 4️⃣ Add a helper to fetch the latest MFA code

```ts
export async function getMfaCode(phoneId: string, apiKey: string) {
  try {
    const headers = {
      'x-api-key': apiKey,
      'Content-Type': 'application/json',
    };
    const response = await fetch(`https://programmatic-api.client.get.mymfa.io/v1/${phoneId}/mfa/latest`, { headers });
    const data = await response.json();
    const mfaCode = data.mfaCode;
    return mfaCode;
  } catch (error) {
    console.error('MFA retrieval error', error);
    throw error;
  }
}
```

#### 5️⃣ Keep secrets out of your code

```ts
import { test, expect } from '@playwright/test'
import * as dotenv from 'dotenv'
dotenv.config()

const PHONE_NUMBER_ID = process.env.GETMYMFA_PHONE_NUMBER_ID!
const API_KEY = process.env.GETMYMFA_API_KEY!
const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL!
const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD!

const GETMYMFA_DEMO_URL = 'https://demo.mymfa.io/login'
```

#### 6️⃣ Put it together in a Playwright test

```ts
test('E2E Login with SMS-based MFA', async ({ page }) => {
  // Navigate to the demo page and confirm title
  await page.goto(GETMYMFA_DEMO_URL)
  await expect(page).toHaveTitle(/GetMyMFA/)

  // Fill in login fields and start sign-in
  await page.getByRole('textbox', { name: 'Email' }).fill(TEST_USER_EMAIL)
  await page.getByRole('textbox', { name: 'Password' }).fill(TEST_USER_PASSWORD)
  await page.getByRole('button', { name: 'Login', exact: true }).click()

  // Ensure MFA prompt is visible
  await expect(page.getByText('MFA Time')).toBeVisible()

  // Fetch MFA code via GetMyMFA API
  const mfaCode = await getMfaCode(PHONE_NUMBER_ID, API_KEY)

  // Submit code and confirm success
  await page.getByRole('textbox', { name: 'MFA Code' }).fill(mfaCode)
  await page.getByRole('button', { name: 'Submit' }).click()

  await expect(page.getByText('MFA code verified')).toBeVisible()
})
```

## ✅ Best Practices for MFA Test Automation

#### 🔒 Security Considerations

- **Environment Isolation:** Use **dedicated test environments** with separate MFA configurations
- **API Key Management:** Store API keys as **environment variables or CI secrets**, never in source code

#### 🎯 Test Reliability

- **Stable Selectors:** Use **data-testid attributes** or stable IDs rather than CSS classes
- **Retry Logic:** Implement **retries for MFA code retrieval** with exponential backoff

#### 🚀 CI/CD Integration

- **Parallel Execution:** Use **unique virtual numbers** for parallel test runs
- **Environment Variables:** Configure **API credentials through CI** environment variables
- **Monitoring:** Set up **alerts for test failures** related to MFA workflows

## 💭 Final thoughts

Automating MFA testing with Playwright and GetMyMFA enables **comprehensive end-to-end testing without compromising security**. This approach ensures that **critical authentication flows are thoroughly validated** in conditions that mirror production environments.

By integrating realistic MFA testing into your automation suite, you can **catch integration issues early**, validate user experience flows, and **maintain confidence in your application's security mechanisms**. The investment in proper MFA test automation pays dividends in **reduced manual testing effort and increased deployment confidence**.

**Start automating your MFA workflows today** and bring production-like security validation to your testing pipeline. Your QA team and users will benefit from the **improved reliability and security assurance**.

## Next steps

- [Download Source Code](https://github.com/jbernales5/getmymfa-playwright-demo)
- [Sign up to GetMyMFA](https://get.mymfa.io/signup)
- [Get in Touch](mailto:hello@mymfa.io?subject=MFA Testing with Playwright - Question)

## Related

- Feature hub: [MFA test automation API](https://get.mymfa.io/features/test-automation)
- [Automate MFA Testing with Selenium — Tutorial, Code & Best Practices](https://get.mymfa.io/blog/selenium-e2e-mfa) ([markdown](https://get.mymfa.io/blog/selenium-e2e-mfa.md))
- [Automate MFA Testing with Cypress — Tutorial, Code & Best Practices](https://get.mymfa.io/blog/cypress-e2e-mfa) ([markdown](https://get.mymfa.io/blog/cypress-e2e-mfa.md))
- [Using webhooks to industrialize MFA Testing](https://get.mymfa.io/blog/webhook-feature) ([markdown](https://get.mymfa.io/blog/webhook-feature.md))

---

GetMyMFA: https://get.mymfa.io. All guides: https://get.mymfa.io/blog. Machine-readable index: https://get.mymfa.io/llms.txt
