What if I told you that you can take your existing Playwright UI test and convert it into a pure API test with the help of AI? No manual request-by-request rewriting. Just record, clean, prompt, and let AI generate the test for you.
I actually did this, and it works. In this article, I'll walk you through the exact workflow I used to generate API tests with AI in Playwright, step by step. Let's dive in.
Why convert UI tests to API tests?
Let's talk about the why first.
UI tests are great for validating the user experience. But they come with baggage. They're slow. They depend on the browser. They break when someone changes a button label or moves an element on the page.
API tests? Fast, stable, and focused on business logic.
If your UI test is just creating data, validating it exists, and deleting it, you don't need a browser for that. The browser is just a middleman sending API requests to the backend. Cut out the middleman, and you get a test that runs in a fraction of the time with much less flakiness.
The problem is that manually rewriting UI tests as API tests is very time-consuming. You need to figure out which endpoints the UI calls, what payloads it sends, and what responses it receives, and then reconstruct all of that in your API testing framework.
What if AI could do this for you?
The workflow: UI test to API test in 4 steps
Here's the high-level pipeline:
Record the network activity of your UI test using Playwright's HAR recording
Clean the HAR file to keep only the relevant API calls
Prepare instructions and a prompt for the AI agent
Generate the API test by feeding everything into an AI coding assistant
Let's break them down.
Step 1: Record network activity with Playwright HAR
Playwright has a built-in feature called recordHar that captures all network traffic during a test run. Every request the browser makes, and every response it receives, is saved in a HAR (HTTP Archive) file.
To enable it, add the recordHar option to your browser context:
const context = await browser.newContext({ recordHar: { path: 'output.har', mode: 'minimal' }});
The mode: 'minimal' setting is important. Without it, Playwright records everything, including response bodies for all resources, and the file gets huge. Minimal mode keeps things manageable.
You can learn more about HAR recording in the official Playwright documentation.
For this demo, I started with a simple UI test in the Conduit Bondar Academy application. The test does basic CRUD operations:
Log in to the application
Create a new article
Validate the article was created
Navigate to the global feed and verify the article appears
Delete the article
Validate the article is removed from the global feed
import { test, expect, request } from '@playwright/test';test('Create and delete article', async ({ page, request }) => { const context = await browser.newContext({ recordHar: { path: 'output.har', mode: 'minimal' } }); const page = await context.newPage(); await page.goto('/') await page.getByText('Sign in').click() await page.getByRole('textbox', { name: 'Email' }).fill(process.env.PROD_USERNAME!) await page.getByRole('textbox', { name: 'password' }).fill(process.env.PROD_PASSWORD!) await page.getByRole('button', { name: 'Sign in' }).click() await page.getByText('New Article').click() await page.getByRole('textbox', { name: 'Article Title' }).fill('Playwright is awesome') await page.getByRole('textbox', { name: 'What\'s this article about?' }).fill('About the Playwright') await page.getByRole('textbox', { name: 'Write your article (in markdown)' }).fill('We like to use playwright for automation') await page.getByRole('button', { name: 'Publish Article' }).click() await expect(page.locator('.article-page h1')).toContainText('Playwright is awesome') await page.getByText('Home').first().click() await page.getByText('Global Feed').click() await page.getByText('Playwright is awesome').click() await page.getByRole('button', { name: "Delete Article" }).first().click() await page.getByText('Global Feed').click() await expect(page.locator('app-article-list h1').first()).not.toContainText('This is a test title')})
After running this test with HAR recording enabled, Playwright generates an output.har file. This is a JSON document containing every single network request the browser made during the test.
And when I say every request, I mean it. The generated HAR file was almost 3,000 lines long. It includes the API calls we care about, as well as JavaScript bundles, images, and other static resources that have nothing to do with our API test.
We need to clean this up before feeding it to AI.
Step 2: Clean and filter the HAR file
A raw HAR file is too noisy for AI to work with. If you feed 3,000 lines of mixed network traffic into an AI agent, you'll get confused output. Clean input produces clean output.
I created a simple Node.js script, har-converter.js, that performs the filtering. It filters by URL to keep only requests to the Conduit API endpoints, removes properties like headers, cookies, HTTP version, and body size, strips out static resources like JavaScript files and images, and keeps only what matters: the request method, URL, request body, and response data.
import { readFileSync, writeFileSync } from 'fs';function filterAndSaveConduitApiEntries(inputFilename, outputFilename) { try { // Read and parse the file const fileContent = readFileSync(inputFilename, 'utf8'); const harObject = JSON.parse(fileContent); // Filter entries and clean up unwanted properties in one step harObject.log.entries = harObject.log.entries .filter(entry => { const url = entry.request.url; return url.includes('conduit-api') && !url.toLowerCase().endsWith('.jpeg'); }) .map(entry => { // Clean up request object if (entry.request) { entry.request.headers = []; delete entry.request.cookies; delete entry.request.httpVersion; delete entry.request.headersSize; delete entry.request.bodySize; } // Clean up response object if (entry.response) { entry.response.headers = []; delete entry.response.cookies; delete entry.response.httpVersion; delete entry.response.statusText; delete entry.response.headersSize; delete entry.response.bodySize; delete entry.response.redirectURL; } // Remove top-level properties delete entry.cache; delete entry.timings; return entry; }); // Write the filtered HAR to file const jsonString = JSON.stringify(harObject, null, 2); writeFileSync(outputFilename, jsonString, 'utf8'); console.log(`Filtered HAR saved to: ${outputFilename}`); } catch (error) { console.error('Error processing file:', error); throw error; }}filterAndSaveConduitApiEntries('output.har', 'filtered-har.json');
Running it:
node har-converter.js
The result? A filtered-har.json file with only 400 lines instead of 3,000. That's the API traffic we actually care about: the login request, the article creation, the GET requests, and the delete operation.
Much better.
So what do we have so far? A clean JSON file that contains only the API requests and responses related to our test flow. Each entry has the HTTP method, the URL, the request body (if any), and the response. This is exactly the information an AI agent needs to reconstruct the same operations as standalone API calls.
Step 3: Prepare AI instructions and prompt
This is where most people get it wrong. They dump a HAR file into the AI agent (in my example, GitHub Copilot) and say, "Make me an API test." That produces garbage.
Why?
Because AI needs context. It needs to understand your framework, your patterns, your naming conventions, and exactly how to interpret the HAR data. The quality of your instructions directly determines the quality of the generated test.
I prepared three documents.
Framework description (copilot-instructions.md)
This document explains how my custom API testing framework works: the technologies used (Playwright-based), the project structure, the design patterns (custom methods like path(), params(), getRequest()), the schema validation approach (shouldMatchSchema()), and how authentication is handled (automatically by the framework).
The AI needs to know what "good code" looks like in your project. Without this, it will generate generic Playwright API calls that don't match your framework's style.
HAR processing instructions (`har-processing.instructions.md`)
This document teaches the AI how to read the HAR JSON structure. Where to find the request method (entries.request.method), the URL (entries.request.url), the request body (entries.request.postData.text). How to extract path segments and query parameters. How to create variables from response data for use in subsequent requests. How to use the faker library for dynamic test data generation.
The examples of the prompts can be found in the GitHub repo. If you want the AI to create a variable from a response and use it in the next request, give it a concrete example of exactly that.
For instance, when the AI creates an article via POST request, the response contains a slug. That slug needs to be extracted and used in the next GET request to retrieve the article details. My instruction document showed this exact pattern:
### 4. Dynamic Value Usage```typescript// Example: Create article, then get it by slugconst createResponse = await api .path('/articles') .body(articleData) .postRequest(201)const articleSlug = createResponse.article.slugconst getResponse = await api .path(`/articles/${articleSlug}`) .getRequest(200)```
Without this kind of concrete example, the AI might hardcode values or miss the connection between requests entirely. The more examples you provide, the better.
The prompt
With the instructions in place, the actual prompt is surprisingly short:
"Process the provided HAR file and create a single comprehensive API test."
It references the instruction documents and includes basic task steps. That's it. The heavy lifting is in the instructions, not the prompt.
Invest your time in writing good instructions. The instructions are reusable across every test you generate. The prompt is just the trigger.
Step 4: Generate the API test with AI
Now we feed everything into the AI agent. I used GitHub Copilot's agent mode in VS Code, but this workflow works with any AI coding assistant that supports file context (Claude, Cursor, etc.).
Add to the context:
filtered-har.json- the cleaned HAR fileHAR processing instructions
The generation prompt
Hit enter and let the AI cook.
The agent analyzed the HAR file, looked at my project's existing code for reference, and produced a complete API test.
A few things stood out:
It followed the step-by-step pattern from the instructions
It used the faker library for test data (it found the
RandomGeneratorclass in the project on its own)It correctly chained responses, using the article slug from the create response in subsequent requests
It matched the framework's custom method syntax
The AI didn't just blindly translate HTTP calls. It understood the framework patterns and produced a test that fits right into the existing codebase.
Tips for better AI-generated API tests
Instructions matter more than prompts
Your instructions document is the most important piece. It's reusable and provides AI with the context it needs. Spend 80% of your effort there. A great instruction file with a one-line prompt will produce better results.
Clean your input data
If you feed a raw 3,000-line HAR file to AI, don't be surprised when the output is messy. Take the time to filter and clean. 400 focused lines beat 3,000 noisy ones every time.
Show variable chaining with examples
The trickiest part for AI is understanding that response data from request A needs to be stored and used in request B. Give explicit examples of this pattern in your instructions. Without them, the AI will either hardcode values or skip the connection between requests.
Always review the output
AI gives you a head start, not a finished product. Review the generated test, check that the assertions make sense for your business logic, and add any validation that the AI missed. You still need to understand what the test is doing.
Also, if your framework supports schema validation, make sure your instructions tell the AI to include it. Contract testing catches bugs that simple property checks will never find.
What about other AI tools?
I used GitHub Copilot's agent mode in this example. But this approach is not limited to Copilot. You can use the same workflow with Claude in VS Code, with Cursor, or with any AI assistant that lets you provide file context.
It doesn't matter which AI you use. What matters is the quality of your instructions and the cleanliness of your input data.
Final Thoughts
Converting UI tests to API tests doesn't have to be a manual process. With Playwright's HAR recording, a cleanup script, and well-written AI instructions, you can generate API tests in minutes instead of hours.
The generated test won't be perfect every time. But it gets you most of the way there. Tweak it, add your business-specific assertions, and you've got a fast, stable API test replacing a slow UI test.
The real investment is in your instruction documents. Write them well once, and every test you generate after that benefits from it.
Playwright is growing in popularity on the market very quickly, and API testing is becoming an essential skill for every test automation engineer. Get the new skills at Bondar Academy with the Playwright API Testing Mastery program. Start from scratch and become an expert to increase your value on the market!
Frequently Asked Questions
What is a HAR file in Playwright?
HAR stands for HTTP Archive. It's a JSON file that logs all network requests and responses during a browser session. In Playwright, you record HAR files using the recordHar option on the browser context.
Can I generate API tests with AI without a custom framework?
Yes. The workflow works with standard Playwright calls too. Adjust your instructions to describe vanilla Playwright API syntax instead of custom methods. The HAR capture and cleanup steps stay the same.
Which AI tool is best for generating Playwright API tests?
The tool matters less than the instructions you give it. GitHub Copilot, Claude, and Cursor all work. Provide clean HAR data and detailed framework instructions, and any of them will produce good output.
How do I handle authentication in AI-generated API tests?
If your framework handles auth automatically (like using Playwright's storageState), tell the AI in your instructions to skip login requests from the HAR file. If you need explicit auth, include an example of your authentication pattern so the AI can replicate it.
Do AI-generated tests need manual review?
Always. The output is typically 80-90% correct, but you should check assertions for business-logic accuracy, verify variable chaining across requests, and add any domain-specific validation the AI missed.
What if the AI generates incorrect API tests from my HAR file?
Usually, it's because the input data is noisy or the instructions are too vague. Filter your HAR file to only relevant API calls and include concrete examples of the expected output format in your instructions.
