Fill out a job application form
Navigate to a sandbox job listing, open the application tab, fill in personal details, and submit the form.
- A Browserless API token from your account dashboard
Steps
This example uses a Browserless sandbox site that simulates a job listing with an application form behind a tab. You can safely test form automation without submitting real applications.
The workflow navigates to the job listing, clicks the "Application" tab to reveal the form, fills in name, email, and a cover message, then clicks "Submit Application".
- AI Agent
- REST API
- Frameworks
- BQL
Use the Browserless MCP server to fill out a job application from any MCP-compatible AI agent (Claude Desktop, Cursor, Windsurf, ChatGPT, etc.).
1. Connect the MCP server
Send this prompt to your AI agent to install the Browserless MCP server:
Go to https://github.com/browserless/browserless-mcp/blob/main/install.md
and follow the instructions to install the Browserless MCP server
for my client.
2. Fill out the application
Use browserless_agent. The task requires interaction: clicking a tab, filling fields, and clicking submit.
Use the browserless_agent tool to go to
https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines,
click the "Application" tab, fill in "Jane Smith" for name,
"jane@example.com" for email, "Excited to contribute to the team!"
as the cover message, and click "Submit Application"
Send the BQL mutation over HTTP to fill and submit the form. This is a sandbox site, so no stealth mode is needed.
- cURL
- JavaScript
- Python
- Java
- C#
1. Send the request
curl -X POST \
"https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation FillJobApplication { goto(url: \"https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines\", waitUntil: networkIdle) { status } clickApplicationTab: click(selector: \"button:nth-child(2)\") { time } waitForInputs: waitForSelector(selector: \"input[type=text]\", timeout: 10000) { time } typeName: type(selector: \"input[type=text]\", text: \"Jane Smith\") { time } typeEmail: type(selector: \"input[type=email]\", text: \"jane@example.com\") { time } typeMessage: type(selector: \"textarea\", text: \"Excited to contribute to the team!\") { time } submit: click(selector: \"div > button:only-of-type\") { time } }",
"variables": {}
}'
2. Check the output
{
"data": {
"goto": { "status": 200 },
"clickApplicationTab": { "time": 179 },
"waitForInputs": { "time": 6 },
"typeName": { "time": 1291 },
"typeEmail": { "time": 1948 },
"typeMessage": { "time": 4547 },
"submit": { "time": 169 }
}
}
1. Send the request
const query = `mutation FillJobApplication {
goto(url: "https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines", waitUntil: networkIdle) {
status
}
clickApplicationTab: click(selector: "button:nth-child(2)") {
time
}
waitForInputs: waitForSelector(selector: "input[type=text]", timeout: 10000) {
time
}
typeName: type(selector: "input[type=text]", text: "Jane Smith") {
time
}
typeEmail: type(selector: "input[type=email]", text: "jane@example.com") {
time
}
typeMessage: type(selector: "textarea", text: "Excited to contribute to the team!") {
time
}
submit: click(selector: "div > button:only-of-type") {
time
}
}`;
const response = await fetch(
'https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: {} }),
}
);
const result = await response.json();
console.log(JSON.stringify(result, null, 2));
2. Check the output
{
"data": {
"goto": { "status": 200 },
"clickApplicationTab": { "time": 179 },
"waitForInputs": { "time": 6 },
"typeName": { "time": 1291 },
"typeEmail": { "time": 1948 },
"submit": { "time": 169 }
}
}
1. Install dependencies
pip install requests
2. Send the request
import requests
query = """
mutation FillJobApplication {
goto(url: "https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines", waitUntil: networkIdle) {
status
}
clickApplicationTab: click(selector: "button:nth-child(2)") {
time
}
waitForInputs: waitForSelector(selector: "input[type=text]", timeout: 10000) {
time
}
typeName: type(selector: "input[type=text]", text: "Jane Smith") {
time
}
typeEmail: type(selector: "input[type=email]", text: "jane@example.com") {
time
}
typeMessage: type(selector: "textarea", text: "Excited to contribute to the team!") {
time
}
submit: click(selector: "div > button:only-of-type") {
time
}
}
"""
response = requests.post(
'https://production-sfo.browserless.io/chromium/bql',
params={'token': 'YOUR_API_TOKEN_HERE'},
json={'query': query, 'variables': {}},
)
print(response.json())
3. Check the output
{
"data": {
"goto": { "status": 200 },
"clickApplicationTab": { "time": 179 },
"typeName": { "time": 1291 },
"typeEmail": { "time": 1948 },
"submit": { "time": 169 }
}
}
1. Send the request
import java.net.URI;
import java.net.http.*;
String token = "YOUR_API_TOKEN_HERE";
String endpoint = "https://production-sfo.browserless.io/chromium/bql?token=" + token;
String query = "mutation FillJobApplication {"
+ " goto(url: \\\"https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines\\\", waitUntil: networkIdle) { status }"
+ " clickApplicationTab: click(selector: \\\"button:nth-child(2)\\\") { time }"
+ " waitForInputs: waitForSelector(selector: \\\"input[type=text]\\\", timeout: 10000) { time }"
+ " typeName: type(selector: \\\"input[type=text]\\\", text: \\\"Jane Smith\\\") { time }"
+ " typeEmail: type(selector: \\\"input[type=email]\\\", text: \\\"jane@example.com\\\") { time }"
+ " typeMessage: type(selector: \\\"textarea\\\", text: \\\"Excited to contribute to the team!\\\") { time }"
+ " submit: click(selector: \\\"div > button:only-of-type\\\") { time }"
+ " }";
String payload = "{\"query\": \"" + query + "\", \"variables\": {}}";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
2. Check the output
{
"data": {
"goto": { "status": 200 },
"typeName": { "time": 1291 },
"submit": { "time": 169 }
}
}
1. Send the request
using System.Net.Http;
using System.Text;
using System.Text.Json;
string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"https://production-sfo.browserless.io/chromium/bql?token={token}";
var payload = new
{
query = @"mutation FillJobApplication {
goto(url: ""https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines"", waitUntil: networkIdle) { status }
clickApplicationTab: click(selector: ""button:nth-child(2)"") { time }
waitForInputs: waitForSelector(selector: ""input[type=text]"", timeout: 10000) { time }
typeName: type(selector: ""input[type=text]"", text: ""Jane Smith"") { time }
typeEmail: type(selector: ""input[type=email]"", text: ""jane@example.com"") { time }
typeMessage: type(selector: ""textarea"", text: ""Excited to contribute to the team!"") { time }
submit: click(selector: ""div > button:only-of-type"") { time }
}",
variables = new { },
};
using (HttpClient httpClient = new HttpClient())
{
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(endpoint, content);
string body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
2. Check the output
{
"data": {
"goto": { "status": 200 },
"typeName": { "time": 1291 },
"submit": { "time": 169 }
}
}
Connect a headless browser to the sandbox job listing, click the Application tab, fill in each field, and submit.
- Puppeteer
- Playwright
- BAP
1. Install dependencies
npm install puppeteer-core
2. Connect and fill the form
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE',
});
try {
const page = await browser.newPage();
await page.goto('https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines', {
waitUntil: 'networkidle2',
});
const buttons = await page.$$('button');
for (const btn of buttons) {
const text = await btn.evaluate((el) => el.innerText);
if (text.trim() === 'Application') {
await btn.click();
break;
}
}
await page.waitForSelector('input[type="text"]');
await page.type('input[type="text"]', 'Jane Smith');
await page.type('input[type="email"]', 'jane@example.com');
await page.type('textarea', 'Excited to contribute to the team!');
const submitButtons = await page.$$('button');
for (const btn of submitButtons) {
const text = await btn.evaluate((el) => el.innerText);
if (text.trim() === 'Submit Application') {
await btn.click();
break;
}
}
console.log('Application submitted successfully');
} finally {
await browser.close();
}
3. Check the output
Run with node fill-job-application.mjs. The script logs a confirmation message after submission.
1. Install dependencies
npm install playwright-core
2. Connect and fill the form
import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE'
);
try {
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines', {
waitUntil: 'networkidle',
});
await page.getByRole('button', { name: 'Application' }).click();
await page.waitForSelector('input[type="text"]');
await page.fill('input[type="text"]', 'Jane Smith');
await page.fill('input[type="email"]', 'jane@example.com');
await page.fill('textarea', 'Excited to contribute to the team!');
await page.getByRole('button', { name: 'Submit Application' }).click();
console.log('Application submitted successfully');
} finally {
await browser.close();
}
3. Check the output
Run with node fill-job-application.mjs. The script logs a confirmation message after submission.
1. Install dependencies
npm install @browserless.io/bap-ts
2. Connect and apply
import Browserless from '@browserless.io/bap-ts';
const browser = Browserless.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io/chromium/bql',
token: 'YOUR_API_TOKEN_HERE',
});
try {
const page = await browser.newPage();
await page.goto('https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines', { waitUntil: 'networkIdle' });
await page.click('button:nth-child(2)');
await page.waitForSelector('input[type=text]', { timeout: 10000 });
await page.type('input[type=text]', 'Jane Smith');
await page.type('input[type=email]', 'jane@example.com');
await page.type('textarea', 'Excited to contribute to the team!');
await page.click('div > button:only-of-type');
} finally {
// Always close to release the session even on error.
await browser.close();
}
3. Check the output
Each call returns once the server has applied it, so the steps stay in order without manual waits between them.
1. Write the mutation
Navigate to the job listing, click the Application tab, fill in the form fields, and submit. This is a sandbox site, so no stealth mode is needed.
mutation FillJobApplication {
goto(url: "https://scraping-sandbox.netlify.app/helix/software-engineer-pipelines", waitUntil: networkIdle) {
status
}
clickApplicationTab: click(selector: "button:nth-child(2)") {
time
}
waitForInputs: waitForSelector(selector: "input[type=text]", timeout: 10000) {
time
}
typeName: type(selector: "input[type=text]", text: "Jane Smith") {
time
}
typeEmail: type(selector: "input[type=email]", text: "jane@example.com") {
time
}
typeMessage: type(selector: "textarea", text: "Excited to contribute to the team!") {
time
}
submit: click(selector: "div > button:only-of-type") {
time
}
}
2. Run it
Paste into the BQL IDE and click Run.
3. Check the output
The response confirms each step completed:
{
"data": {
"goto": { "status": 200 },
"clickApplicationTab": { "time": 179 },
"waitForInputs": { "time": 6 },
"typeName": { "time": 1291 },
"typeEmail": { "time": 1948 },
"typeMessage": { "time": 4547 },
"submit": { "time": 169 }
}
}