Grid image CAPTCHAs present a 3×3 or 4×4 grid with an instruction like "select all squares with traffic lights." This tutorial shows how to solve them from Node.js using CaptchaAI and Puppeteer.
Prerequisites
| Item | Value |
|---|---|
| CaptchaAI API key | From captchaai.com |
| Node.js | 14+ |
| Libraries | axios, puppeteer |
Step 1: Capture the grid image
const puppeteer = require('puppeteer');
const fs = require('fs');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/page-with-recaptcha');
// Switch to the reCAPTCHA challenge iframe
const frames = page.frames();
const challengeFrame = frames.find((f) => f.url().includes('recaptcha/api2/bframe'));
// Get the instruction text
const instruction = await challengeFrame.$eval(
'.rc-imageselect-desc-no-canonical',
(el) => el.textContent.trim()
);
// Screenshot the grid
const grid = await challengeFrame.$('.rc-imageselect-target');
await grid.screenshot({ path: 'grid.png' });
Step 2: Submit to CaptchaAI
const axios = require('axios');
const FormData = require('form-data');
const API_KEY = 'YOUR_API_KEY';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const form = new FormData();
form.append('key', API_KEY);
form.append('method', 'post');
form.append('grid_size', '3x3');
form.append('img_type', 'recaptcha');
form.append('instructions', instruction);
form.append('json', '1');
form.append('file', fs.createReadStream('grid.png'));
const { data: submitData } = await axios.post('https://ocr.captchaai.com/in.php', form, {
headers: form.getHeaders(),
});
if (submitData.status !== 1) throw new Error(submitData.request);
const taskId = submitData.request;
console.log(`Task submitted: ${taskId}`);
Step 3: Poll for the solution
await sleep(5000);
let cellsToClick;
for (let i = 0; i < 30; i++) {
const { data: pollData } = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
});
if (pollData.status === 1) {
cellsToClick = JSON.parse(pollData.request);
console.log('Click cells:', cellsToClick);
break;
}
if (pollData.request !== 'CAPCHA_NOT_READY') {
throw new Error(pollData.request);
}
await sleep(5000);
}
Step 4: Click the correct tiles
const tiles = await challengeFrame.$$('.rc-imageselect-tile');
for (const cellNum of cellsToClick) {
await tiles[cellNum - 1].click();
await sleep(300);
}
// Click verify
await challengeFrame.click('#recaptcha-verify-button');
console.log(`Solved: clicked tiles ${JSON.stringify(cellsToClick)}`);
await browser.close();
Expected output:
Click cells: [1, 3, 6, 9]
Solved: clicked tiles [1,3,6,9]
FAQ
Does this work with 4×4 grids?
Yes. Set grid_size to 4x4 in the request parameters.
Can I use Playwright instead of Puppeteer?
Yes. The CaptchaAI API calls are the same — only the browser automation code changes.
What if the CAPTCHA refreshes with new images?
Some reCAPTCHA challenges load new tiles. You may need to capture and submit again for each round.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.