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
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. 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 }
}
}
Next steps
- Fill and Submit a Form -- more form automation examples including CAPTCHA solving
- Authenticated Sessions -- persist login state across requests
- Take a Screenshot -- capture the confirmation page after submission