Home / Services / Dedicated Playwright engineers
Hire dedicated Playwright engineers from a company that does nothing else
The engineer who joins your standup has spent their career in this one framework, so the first fortnight goes on your suite instead of on the documentation.
An engineer of ours works on your Playwright suite, in your repository and your CI. The company is 75 engineers across four countries — one onshore, one nearshore and two offshore for a US client — and all 75 work in Playwright. Engineers are billed hourly, from $50 an hour, minimum one full-time engineer for one month.
The first email is about the role and not about your suite: what the person would pick up, whose backlog it comes off, and whether anyone on your side can answer a question about the application on the day it is asked.
Who this is for
Leads who have Playwright work in front of them and not enough people to do it. Usually it is one of these.
- One engineer built the suite and has left, moved to another product, or is now the only person who understands a thing forty other people depend on. The suite still runs. Nobody is developing it.
- A senior automation req that has been open since the spring, and somebody in a planning meeting has started asking whether contract capacity moves this quarter instead of the next one.
- You have bought contract capacity before, and the ramp-up was on your invoice: an engineer arrived who had Playwright on a CV, and week three was still going on fixtures.
A team that needs one permanent person, in one office, for the next five years should hire one. That is a different purchase from this and nothing here beats it — an employee accrues context about your product that a contractor is always behind on. This buys the Playwright half of that person, available before the req closes.
Two neighbouring problems are not a headcount gap. If the work is a bounded piece — a suite built from scratch on a product that has none — that is an end-to-end suite built in your repository, scoped as a project. If the suite exists and the reason nobody is happy is that it goes red at random, the engagement that ranks the intermittent specs and fixes them is flaky suite repair.
Who you get, and where they sit
The company is 75 engineers and all 75 work in Playwright. There is no Playwright practice inside a wider testing business here, because there is no wider business: one framework is the whole company, which is why an engineer joining your team has already met the suite you own — not yours, but its shape. The login through the UI on every test. The page object copied off a blog in 2023.
| Location | For a US client | Engineers |
|---|---|---|
| United States | Onshore | 10 |
| Argentina | Nearshore | 20 |
| Poland | Offshore | 30 |
| Ukraine | Offshore | 15 |
The middle column is written from a US buyer's seat. Onshore, nearshore and offshore describe a distance from somebody, and the somebody here is a client in the United States; a lead reading this from Berlin should read the first and third columns and ignore the second.
Argentina is the location whose working day overlaps a United States one, and it is the answer when the requirement is a person in your standup rather than a handover note waiting in the morning. The arithmetic is a fact about the clocks rather than about us, so here it is. Buenos Aires is UTC-3 and stays there: Argentina has not moved its clocks since 2009, and the United States does move, which is why the gap changes twice a year and why it is the American end that changes it. From March to November the gap to US Eastern is one hour and to Pacific four; the rest of the year it is two and five.
Converted, a nine-to-six day in Buenos Aires is 08:00 to 17:00 Eastern in the American summer and 07:00 to 16:00 in the winter — the first of those covers a nine-to-five Eastern day end to end, and the second covers all but its last hour. Against a Pacific team the same day runs 05:00 to 14:00, so the shared window is 09:00 to 14:00 Pacific, and four hours rather than five once the clocks go back. The hours an individual engineer is contracted for are not published here; ask for them on the call.
What you get
An engagement here hands over a person and the things a person leaves behind.
An engineer in your standup, on your board
They take tickets from your backlog, in your tracker, prioritised by whoever prioritises everyone else's — a spec, a fixture, a shard that times out in CI. They are in the standup, the retro and the release channel. Questions about your application go to your people and not through an account manager, which is the arrangement that decides whether the first week produces a merged test or a list of blockers.
Their work in your repository, in your CI
Branches on your remote, pull requests under your branch rules, reviewed by your engineers and merged by them. It runs in your pipeline on your runners. Nothing is staged in a vendor repository and handed over at the end, so there is no day on which you take delivery of anything: you own every commit from the first one.
A named replacement path
What happens if the fit is wrong, or the person is unavailable for a stretch, agreed before anybody starts, while nobody is under pressure.
How it works
The role, then the person
You describe the work: what is in the backlog, what the suite is written in today, what you would want merged in the first month. We come back with who is available and where they sit. We publish no lead time, because it moves with which location has somebody free and how fast access clears on your side; ask for a date and you get the one that is real that week.
Access, and one person who answers questions
Your side of it is short, and it is the whole critical path: write access to the repository, an account on your CI, credentials for a test environment, and the name of one person who can answer a question about the application the day it is asked. An engineer without that last one spends the first days reading the product instead of testing it.
Directed by your team
Your backlog, your priorities, your reviewers, our engineer. They are not managed from here and there is no parallel plan running alongside yours. Whether it is working shows the same way it shows for anyone else on the team, inside the first month: what merged, and what it broke.
What a specialist writes in week one
Below is what an engineer writes, beside what the same decision looks like in a suite built by somebody who was learning the framework as they went. The second version in each pair gets written on the first morning, before there is a suite to fix.
The samples below were written against Playwright 1.62.The login, and it is most of the bill
A test needs an authenticated page. This is the version that ends up copied into every spec file in a suite:
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ page }) => {
await page.goto('https://app.example.com/sign-in');
await page.getByLabel('Work email').fill('rita@example.com');
await page.getByLabel('Password').fill('correct-horse');
await page.getByRole('button', { name: 'Log in' }).click();
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible();
});
test('archives a project', async ({ page }) => {
await page.getByRole('link', { name: 'Apollo' }).click();
await page.getByRole('button', { name: 'Archive' }).click();
await expect(page.getByText('Project archived')).toBeVisible();
});
It works, which is why it survives. It also drives a full browser login once per test, so a four-hundred-spec suite signs in four hundred times a run and pays for it in wall-clock on every pipeline, forever.
Here is the same decision made by somebody who has unpicked this before. A setup project signs in once and writes the browser state to a file:
// tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
import path from 'path';
const authFile = path.join(__dirname, '../playwright/.auth/user.json');
setup('authenticate', async ({ page }) => {
await page.goto('https://app.example.com/sign-in');
await page.getByLabel('Work email').fill('rita@example.com');
await page.getByLabel('Password').fill('correct-horse');
await page.getByRole('button', { name: 'Log in' }).click();
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible();
await page.context().storageState({ path: authFile });
});
The config declares that the setup project runs first and that the test project starts from the state it wrote:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'chromium',
use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
dependencies: ['setup'],
},
],
});
And the spec opens already signed in:
import { test, expect } from '@playwright/test';
test('archives a project', async ({ page }) => {
await page.goto('https://app.example.com/projects');
await page.getByRole('link', { name: 'Apollo' }).click();
await page.getByRole('button', { name: 'Archive' }).click();
await expect(page.getByText('Project archived')).toBeVisible();
});
Two lines in there are the ones worth hiring for. dependencies: ['setup'] is what
makes the setup project run before the tests, and a half-copied version of this pattern fails
exactly there — the state file is missing on the first run and the specs land on a login screen.
And playwright/.auth goes into .gitignore without anybody asking,
because that file holds cookies that can sign in as the test account, and Playwright's
authentication documentation says plainly that it
should not be committed to a repository, private or public. One shared sign-in is the right shape
for a suite whose tests read more than they write; the moment tests start changing
server-side state, the same engineer moves to one account per worker.
The button in the row that moved
A test has to click a control inside one row of a list. Positional selectors are what a suite collects when nobody has been burned yet:
import { test, expect } from '@playwright/test';
test('adds the second product to the cart', async ({ page }) => {
await page.goto('https://shop.example.com/products');
await page.locator('ul.products li:nth-child(3) button').click();
await expect(page.getByText('1 item in cart')).toBeVisible();
});
That passes until somebody changes the default sort, adds a promoted row at the top, or wraps the button in a div. Scope by what the row is, then reach inside it:
import { test, expect } from '@playwright/test';
test('adds Product 2 to the cart', async ({ page }) => {
await page.goto('https://shop.example.com/products');
await page.getByRole('listitem')
.filter({ has: page.getByRole('heading', { name: 'Product 2' }) })
.getByRole('button', { name: 'Add to cart' })
.click();
await expect(page.getByText('1 item in cart')).toBeVisible();
});
The second one survives a re-order and reads like the product. Locators are also strict, so an ambiguous match throws instead of quietly clicking the first thing it found; the long version of that is its own article.
Both decisions get made in the first week and then never opened again, and the wrong version is paid for on every run for as long as the suite lives.
Where this stops
An engineer is a person, and a person can be handed any ticket. So the boundary here is about what the engineer is, and not only about what the framework does.
- They do not become a general QA hire. No manual test execution, no test-case authoring in a management tool, no release coordination, no exploratory pass on the Thursday before a release when the sprint has run short. If the ticket you are quietly planning to give them is "run the regression sheet by hand", that is not us, and finding that out now is cheaper than finding it out in month two.
- They do not become a mobile app tester. Playwright drives browsers. Its device emulation sets a phone-sized viewport, a phone's user agent and touch input, so what an engineer here can cover on a phone is your responsive web. Nothing in that reaches the iOS or Android build your users downloaded, and pointing a person at it does not change what the framework does.
- They do not become a performance engineer. Playwright measures one real browser doing one thing well. It is not k6, JMeter or Gatling, and no engineer here is billed to a load testing engagement.
- They do not become a security or penetration tester. Not offered by this company, in any framework, at any of the four locations.
Two framework limits sit under all of that, and no hire works around them. Playwright's WebKit build is not Safari on an iPhone: its browser documentation states that Playwright does not work with the branded Safari because it relies on patches, so an engineer here cannot bring you coverage on a real iOS device. The framework does not support Internet Explorer at all, and no engagement here writes IE tests.
What it costs
An engineer on this engagement is priced the way every hour here is priced, because it is the same engineer. Engineers are billed hourly, from $50 an hour, depending on where the engineer sits. The minimum engagement is one full-time engineer for one month.
The hourly rate moves with where the engineer sits, and no per-location figure is published on this site because none has been confirmed, so the table further up is not a price list. There is no monthly total on this page either: multiplying an hourly rate by a month means assuming how many hours are in one, and that is a number nobody here has given you.
Read first
Decisions an embedded engineer makes in their first fortnight, written out at length. They are also the fastest way to judge whether the person you are about to hire agrees with us.
- Playwright fixtures. The setup model the first
sample above turns on, and the thing a suite is missing when every spec has its own
beforeEach. - Page objects in Playwright. The structural decision every new engineer inherits an opinion about, ours included.
- Playwright best practices. What the engineer measures your suite against from the first pull request.
- Why Playwright tests flake. What a new engineer is usually hired into the middle of.
Questions
How quickly can a Playwright engineer start?
There is no published lead time here, and nothing we have confirmed gives one. It depends on which of the four locations has an engineer free, what the role needs them to know on arrival, and how long your side takes to grant repository and CI access. The number worth putting beside it is one you already hold: how many months your own open req has been open, and how many candidates in it write Playwright every day. Ask for a date in the first email and you get the one that applies to your dates.
Can we start with one engineer?
Yes, and one is a normal size to start at. The model is per engineer, and the minimum engagement is one full-time engineer for one month, so the smallest thing you can buy here is one person, full time, for a month. Adding a second later is the same purchase again.
Where will the engineer be based, and what hours will they work?
In one of four countries: the United States, Argentina, Poland or Ukraine. The company is 75 engineers and all 75 work in Playwright, 10 of them in the United States, 20 in Argentina, 30 in Poland and 15 in Ukraine. Onshore, nearshore and offshore are relative to where the buyer sits, and on this page they are written from a US buyer's seat: one onshore location, one nearshore, two offshore. Argentina is the location whose working day overlaps a United States one, which is what a lead who wants somebody in their own standup is usually asking about. Buenos Aires is UTC-3 and stays there all year, and the United States moves its clocks rather than Argentina, so the gap to US Eastern is one hour from March to November and two hours the rest of the year, and the gap to Pacific is four hours and then five. Converted, a nine-to-six day in Buenos Aires covers a nine-to-five Eastern day end to end in the American summer and all but its last hour in the winter; against a Pacific team the shared window is 09:00 to 14:00, and an hour shorter once the clocks go back. The hours an individual engineer is contracted for are not published, and that is a question to put to us on the call.
What does a dedicated Playwright engineer cost?
Engineers are billed hourly, from $50 an hour, depending on where the engineer sits. The minimum engagement is one full-time engineer for one month. The figure is a floor and not a price, and no per-location rate is published here because none has been confirmed. Nor is there a monthly total on this page: turning an hourly rate into one means assuming how many hours we count in an FTE-month, and nobody has confirmed that number either.
What if the engineer is not the right fit?
Say so early, in week two rather than in month three, and while the work still fits in a handover. Beyond that, there is no replacement policy published here: no window, no guarantee and no notice period, because none of it has been confirmed. A policy invented on a marketing page reads exactly like one somebody agreed to, so this belongs on the call, and it belongs in writing before you sign anything.
Do we need the audit before we start?
No. Nothing has to be bought before this one: you have Playwright work and not enough people to do it, and that is a job you can state in a paragraph. The audit is there for a team that wants to know what it has before it picks a direction. It is optional, it is billed by the hour, and how long it takes depends on the project. The minimum of one full-time engineer for one month does not apply to it.
What is the suite written in now, and when do you want somebody in the standup?
A language and a date are enough to tell you who is available and what the first month would go on. If there is no suite yet, say that instead — it changes who we would put on it. We do not need an audit to start.