There is also an invisible captcha (Invisible Captcha), which has no visible interface on the page and does not require any user actions — verification occurs in the background.
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
String | Required | CustomTask |
class |
String | Required | altcha |
websiteURL |
String | Required | The main page URL where the Altcha is located. |
websiteKey |
String | Required | For this task, sending an empty string is allowed. |
metadata.challenge |
String | Required | Unique task identifier obtained from the website. |
metadata.iterations |
String | Required | Number of iterations or the maximum number for calculations. Important: the iterations parameter corresponds to the maxnumber value! |
metadata.salt |
String | Required | Salt obtained from the site, used for hash generation. Important: Always send the full value of the salt field, including all parameters (edk, codeChallenge, expires, etc.). |
metadata.signature |
String | Required | Digital signature of the request. |
userAgent |
String | Optional | Browser User-Agent. Pass only a valid UA from Windows OS. |
proxyType |
String | Optional | http - regular http/https proxy; https - try this option only if "http" doesn't work; socks4 - socks4 proxy; socks5 - socks5 proxy. |
proxyAddress |
String | Optional | IPv4/IPv6 proxy IP address. Not allowed: transparent proxies or local machine proxies. |
proxyPort |
Integer | Optional | Proxy port. |
proxyLogin |
String | Optional | Proxy server login. |
proxyPassword |
String | Optional | Proxy server password. |
POST https://captcha69.com/createTask
Content-Type: application/json
{
"clientKey": "max1_YOUR_API_KEY",
"task": {
"type": "CustomTask",
"class": "altcha",
"websiteURL": "https://example.com",
"websiteKey": "",
"userAgent": "userAgentPlaceholder",
"metadata": {
"challenge": "3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c",
"iterations": "5000",
"salt": "46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664",
"signature": "4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18"
}
}
}
{
"errorId": 0,
"taskId": 407533072
}
POST https://captcha69.com/createTask
Content-Type: application/json
{
"clientKey": "max1_YOUR_API_KEY",
"task": {
"type": "CustomTask",
"class": "altcha",
"websiteURL": "https://example.com",
"websiteKey": "",
"userAgent": "userAgentPlaceholder",
"metadata": {
"challenge": "3dd28253be6cc0c54d95f7f98c517e68744597cc6e66109619d1ac975c39181c",
"iterations": "5000",
"salt": "46d5b1c8871e5152d902ee3f?edk=1493462145de1ce33a52fb569b27a364&codeChallenge=464Cjs7PbiJJhJZ_ReJ-y9UGGDndcpsnP6vS8x1nEJyTkhjQkJyL2jcnYEuMKcrG&expires=1761048664",
"signature": "4b1cf0e0be0f4e5247e50b0f9a449830f1fbca44c32ff94bc080146815f31a18"
},
"proxyType": "http",
"proxyAddress": "8.8.8.8",
"proxyPort": 8080,
"proxyLogin": "proxyLoginHere",
"proxyPassword": "proxyPasswordHere"
}
}
{
"errorId": 0,
"taskId": 407533072
}
Use the getTaskResult method to obtain the Altcha solution.
POST https://captcha69.com/getTaskResult
Content-Type: application/json
{
"clientKey": "max1_YOUR_API_KEY",
"taskId": 407533072
}
{
"errorId": 0,
"status": "ready",
"solution": {
"data": {
"token": "eyJhbGdvcml...Ljc2MDEzM30==",
"number": 44619
}
}
}
| Property | Type | Description |
|---|---|---|
data.token |
String | Base64-encoded solution containing all captcha parameters (algorithm, challenge, number, salt, signature). |
data.number |
Integer | The numeric solution for the Proof-of-Work challenge. |
Below are examples of extracting Altcha parameters needed to submit a solving task. Note that captcha implementations may differ across websites, so parameter extraction methods may vary.
In general, after activating the captcha on the page, you need to analyze network requests and identify all interactions related to its operation. For example, the screenshot below shows a request named altcha containing all key parameters:
After obtaining the required parameters, you need to pass them into the metadata object when creating a task. Example structure:
metadata: {
challenge: "<challenge value>",
iterations: "<maxnumber value>", // must be enclosed in quotes
salt: "<salt value>",
signature: "<signature value>",
}
const url = 'https://example-portal.mysite.rs.gov.br/Altcha/Example';
fetch(url, { method: 'GET' })
.then(res => res.text())
.then(data => console.log('Response:', data))
.catch(err => console.error(err));
(function() {
const keywords = ['algorithm','challenge','maxnumber','salt','signature'];
const foundParams = {};
const intercept = (url, body, text) => {
keywords.forEach(key => {
if ((url && url.includes(key)) || (body && body.includes(key)) || (text && text.includes(key))) {
foundParams[key] = foundParams[key] || [];
if (url?.includes(key)) foundParams[key].push(url);
if (body?.includes(key)) foundParams[key].push(body);
if (text?.includes(key)) foundParams[key].push(text);
}
});
if (Object.keys(foundParams).length) console.log('Found parameters:', foundParams);
};
const originalFetch = window.fetch;
window.fetch = async (...args) => {
const [resource, config] = args;
const url = typeof resource === 'string' ? resource : resource.url;
const body = config?.body;
const response = await originalFetch.apply(this, args);
try {
const text = await response.clone().text();
intercept(url, body, text);
} catch {}
return response;
};
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
this._url = url;
return originalOpen.call(this, method, url, ...rest);
};
XMLHttpRequest.prototype.send = function(body) {
this.addEventListener('load', () => intercept(this._url, body, this.responseText));
return originalSend.call(this, body);
};
})();
In some cases, submitting just the number parameter is enough to confirm the solution. However, sometimes the site requires all parameters, encoded in base64.
The API returns number separately as well as the full set of parameters encoded in base64 (including number).
const { chromium } = require("playwright");
const API_KEY = "max1_YOUR_API_KEY";
const ALTCHA_PAGE = "https://url_with_altcha";
(async () => {
const browser = await chromium.launch({ headless: false, devtools: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.route("**/*", (route) => {
const url = route.request().url();
if (url.includes("captcha69.com")) return route.abort();
return route.continue();
});
let challengeResp = null;
page.on("response", async (response) => {
try {
if (response.url().includes("/Altcha/GerarDesafio")) {
challengeResp = await response.json();
console.log("Captured /Altcha/GerarDesafio:", challengeResp);
}
} catch {}
});
await page.goto(ALTCHA_PAGE, { waitUntil: "networkidle" });
try {
await page.waitForSelector("altcha-widget input[type='checkbox']", { timeout: 10000 });
await page.click("altcha-widget input[type='checkbox']");
} catch {
const widgetHandle = await page.$("altcha-widget");
if (widgetHandle) await widgetHandle.click();
}
const start = Date.now();
while (!challengeResp && Date.now() - start < 30000) {
await new Promise((r) => setTimeout(r, 300));
}
if (!challengeResp) {
console.error("Failed to capture /Altcha/GerarDesafio.");
await browser.close();
return;
}
const { challenge, salt, signature, maxnumbers } = challengeResp;
const createTaskBody = {
clientKey: API_KEY,
task: {
type: "CustomTask",
class: "altcha",
websiteURL: ALTCHA_PAGE,
websiteKey: "",
userAgent: "userAgentPlaceholder",
metadata: {
challenge,
iterations: maxnumbers,
salt,
signature,
},
},
};
const taskResp = await fetch("https://captcha69.com/createTask", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(createTaskBody),
}).then((r) => r.json());
console.log("CreateTask response:", taskResp);
if (!taskResp || !taskResp.taskId) {
console.error("CreateTask failed:", taskResp);
await browser.close();
return;
}
const taskId = taskResp.taskId;
let fullSolution = null;
const maxPollMs = 120000;
const pollStart = Date.now();
while (Date.now() - pollStart < maxPollMs) {
const res = await fetch("https://captcha69.com/getTaskResult", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ clientKey: API_KEY, taskId }),
}).then((r) => r.json());
if (res.status === "ready") {
fullSolution = res.solution;
console.log("Full solution:", fullSolution);
break;
}
await new Promise((r) => setTimeout(r, 3000));
}
if (!fullSolution) {
console.error("Solution was not received within the allocated time.");
await browser.close();
return;
}
const token =
(fullSolution && fullSolution.data && fullSolution.data.token) ||
fullSolution.token ||
(fullSolution && fullSolution.data) ||
null;
if (!token) {
console.error("Token not found:", fullSolution);
await browser.close();
return;
}
console.log("Token:", token);
await browser.close();
})();