CAPTCHA and AI functions#
Functions that solve captchas through third-party services and call AI models to answer questions, read images or generate images. You need your own account and API key with those services; 9Hits does not provide keys.
API keys in campaign macros
A 9Hits campaign macro runs on the computers of other people who run the Viewer, so any API key written in the macro is sent to those computers too. Use the functions that need an API key in 9Login scripts instead: a 9Login script runs on your own computer.
Solving captchas#
SolveRecaptcha and SolvehCaptcha read the captcha details from the page, send them to the service
you choose, then fill the result into the page. The _2Captcha*, AC* and AZ* functions call one
service directly (2Captcha, Anti-Captcha, Azcaptcha). The ReportBad/ReportIncorrect functions tell
the service that a solve was wrong.
SolveRecaptcha#
Solves the reCAPTCHA on the open page: finds the site key, sends it to the solving service you choose,
waits for the result, then fills the token into the page. After that, submit the form yourself with a
click function; if the page has no submit button, call
TryToCallRecaptchaCallBack.
Parameters
| Name | Description |
|---|---|
service |
Solving service: "2captcha" or "anti-captcha". Any other value makes the function fail immediately. |
apiKey |
Your API key for that service. |
timeout |
Maximum time to wait for the answer, in seconds. Default 300. |
overrideApiServer |
An alternative API address, for when you use another service whose API works like 2Captcha's or Anti-Captcha's. The default null uses the service's own address. |
Returns
The service's result object when the captcha is solved, false on failure (the reason is written
to the log). The token is in result.request for 2Captcha and in
result.solution.gRecaptchaResponse for Anti-Captcha.
Example
SolvehCaptcha#
Same as SolveRecaptcha, but for hCaptcha: finds the site key, sends it to the
solving service, waits for the result, then fills the token into the page. After that, submit the
form yourself.
Parameters
| Name | Description |
|---|---|
service |
Solving service: "2captcha" or "anti-captcha". Any other value makes the function fail immediately. |
apiKey |
Your API key for that service. |
timeout |
Maximum time to wait for the answer, in seconds. Default 300. |
overrideApiServer |
An alternative API address, for when you use another service whose API works like 2Captcha's or Anti-Captcha's. The default null uses the service's own address. |
Returns
Same as SolveRecaptcha: the service's result object when the captcha is solved, false on
failure. The token is in result.request for 2Captcha and in result.solution.gRecaptchaResponse
for Anti-Captcha.
Example
SolveImageCaptcha#
This function does not work yet: calling it solves nothing and returns nothing. To solve an image
captcha, capture the image with CaptureElement and send it with
_2CaptchaSolve or ACSolve, as in the example below.
Syntax
Parameters
| Name | Description |
|---|---|
imgSelector |
CSS selector of the captcha image. |
resultSelector |
CSS selector of the answer input. |
service |
"2captcha" or "anti-captcha". |
apiKey |
Your API key for that service. |
timeout |
Maximum time to wait for the answer, in seconds. Default 300. |
overrideApiServer |
An alternative API address for the service. Default null. |
Example
TryToCallRecaptchaCallBack#
Calls the page's reCAPTCHA callback function with the solved token. Use it on pages that have no
submit button, or that do not react when only the token is filled in. response is the token string,
not the whole result object.
Parameters
| Name | Description |
|---|---|
response |
The solved reCAPTCHA token: result.request from 2Captcha, or result.solution.gRecaptchaResponse from Anti-Captcha. |
frameSearch |
Condition for finding the iframe that holds the reCAPTCHA, used together with frameSearchType; leave it empty for the main frame. See Iframes, selectors and waiting. |
frameSearchType |
How frameSearch is matched: "src-starts", "src-ends", "src-equals", "src-contains", "src-regex" or "frame-path". You must set it when you use frameSearch: if it is empty, the function ignores frameSearch and works on the main frame. |
Example
_2CaptchaSolve#
Sends a solve request to 2Captcha and waits until there is an answer. It works
for every captcha type that 2Captcha supports (image, reCAPTCHA, hCaptcha...); you only need to set
params according to the 2Captcha API documentation.
Parameters
| Name | Description |
|---|---|
params |
Parameter object sent to 2Captcha, following the 2Captcha API documentation. It must contain key (your API key), method (for example "base64" for images, "userrecaptcha" for reCAPTCHA) and json: 1, plus the captcha data that the method needs. |
timeout |
Maximum time to wait for the answer, in seconds. Empty or 0 waits 150 seconds. |
Returns
Object {status, request, captchaId}. When the captcha is solved, status is 1, request is
the answer (or token) and captchaId is the ID of the solve, used by
_2CaptchaReportBad. On failure, status is 0 and request is the
reason: a 2Captcha error code, or "Timed out" when the time runs out.
Example
_2CaptchaReportBad#
Tells 2Captcha that an answer was wrong, so you are not charged for that solve. Report only when you are sure the answer is wrong; do not abuse it.
Parameters
| Name | Description |
|---|---|
key |
Your 2Captcha API key. |
captchaId |
The ID of the solve: captchaId in the result of _2CaptchaSolve, or of SolveRecaptcha when it uses 2Captcha. |
Returns
The 2Captcha HTTP response as {status, headers, body}, like HttpRequest;
you usually do not need it.
Example
ACSolve#
Sends a task to Anti-Captcha and waits until there is an answer.
task.type decides the captcha type, following the Anti-Captcha API documentation.
Parameters
| Name | Description |
|---|---|
params |
Object sent to Anti-Captcha, following the Anti-Captcha API documentation: clientKey is your API key, task describes the captcha to solve (for example {type: "ImageToTextTask", body: base64 image}). If it is not an object, the function returns an error immediately. |
timeout |
Maximum time to wait for the answer, in seconds. Empty or 0 waits 150 seconds. |
Returns
The Anti-Captcha result object. When the captcha is solved, errorId is 0, status is
"ready", the answer is in solution (solution.text for image captchas,
solution.gRecaptchaResponse for reCAPTCHA) and taskId is used to report a wrong solve. On an
error or timeout, errorId is not 0 and errorDescription gives the reason.
Example
ACReportIncorrectImage#
Tells Anti-Captcha that an image captcha was solved wrong. Report only when you are sure the answer is wrong; do not abuse it.
Parameters
| Name | Description |
|---|---|
clientKey |
Your Anti-Captcha API key. |
taskId |
The task ID: taskId in the result of ACSolve. |
Returns
The Anti-Captcha HTTP response as {status, headers, body}; you usually do not need it.
Example
ACReportIncorrectRecaptcha#
Tells Anti-Captcha that a reCAPTCHA was solved wrong. The function sends the report and moves on right away, without returning a result. Report only when you are sure; do not abuse it.
Parameters
| Name | Description |
|---|---|
clientKey |
Your Anti-Captcha API key. |
taskId |
The task ID: taskId in the result of ACSolve, or of SolveRecaptcha when it uses Anti-Captcha. |
Example
AZSolve#
Sends a solve request to Azcaptcha and waits until there is an answer. It
works like _2CaptchaSolve: params follows the Azcaptcha API documentation,
which uses the same style as 2Captcha's.
Parameters
| Name | Description |
|---|---|
params |
Parameter object sent to Azcaptcha: key is your API key, plus method (for example "base64") and the captcha data (for example body). If you do not set json, the function adds json: 1 itself. |
timeout |
Maximum time to wait for the answer, in seconds. Empty or 0 waits 300 seconds. |
Returns
Object {status, request, captchaId}, the same shape as _2CaptchaSolve: status is 1 when the
captcha is solved and request is the answer; on failure, status is 0 and request is the
reason. captchaId is used by AZReportBad.
Example
AZReportBad#
Tells Azcaptcha that a solve was wrong. Report only when you are sure the answer is wrong; do not abuse it.
Parameters
| Name | Description |
|---|---|
key |
Your Azcaptcha API key. |
captchaId |
The ID of the solve: captchaId in the result of AZSolve. |
Returns
The Azcaptcha HTTP response as {status, headers, body}; you usually do not need it.
Example
Calling AI#
PromptAI, GenImageAI and ListAIModels can call many AI providers with the same kind of
parameters, and they always return results in the same shape. These functions do not throw: on an
error, ok is false and the reason is in error.
PromptAI#
Sends a question to an AI model and gets the answer, optionally with images (for example a screenshot
of the open page). All options go in one options object; always check ok before you read text.
Parameters
| Name | Description |
|---|---|
options.provider |
Provider: "openai", "anthropic", "gemini", "openrouter", "deepseek", "groq", "xai", "mistral", "together", "perplexity", "ollama" or "lmstudio". The names "claude", "google", "grok", "local" (meaning ollama) and "lm-studio" also work. If both provider and endpoint are empty, openai is used. |
options.apiKey |
Your API key with that provider. |
options.model |
Model name. If empty, the default is used: gpt-4o-mini (openai), deepseek-chat (deepseek), grok-4 (xai), claude-sonnet-5 (anthropic), gemini-2.5-flash (gemini). For the other providers, and when you use endpoint, it is required. Get the names with ListAIModels. |
options.prompt |
The question, sent as a user message. You need prompt or messages. |
options.system |
System instructions (system prompt), for example a role or how to answer. |
options.messages |
A whole conversation: an array of {role, content, images} where role is "user", "assistant" or "system"; a string element counts as a user message. If prompt is also set, prompt is added at the end. "system" messages are merged into system. |
options.images |
Images to send along, one image or an array: a data URL, a base64 string (like the result of CapturePage), an http(s) URL or an ArrayBuffer. The images are attached to the last user message. image also works. |
options.json |
true to ask for a JSON answer, or a JSON Schema to enforce the exact structure. With anthropic this is only an instruction added to the system prompt, so you still have to check the returned json yourself. |
options.temperature |
How random the answer is; smaller numbers give more consistent answers. Empty uses the provider's default. |
options.topP |
Top-p sampling parameter. Empty uses the provider's default. |
options.maxTokens |
Maximum number of tokens in the answer. Empty lets the provider decide; anthropic requires a limit, so its default is 4096. |
options.stop |
A string or an array of strings; the model stops when it is about to write that string. |
options.timeout |
Timeout for each call, in milliseconds. Default 60000. Each retry gets its own timeout. |
options.retries |
How many times to retry automatically on a network error, rate limiting (HTTP 429) or a temporary server error. Default 2. |
options.useProxy |
true to call through the session's proxy. Default false: call directly from the computer. |
options.proxy |
A proxy for this call only: {type, host, port, username, password}, where type is "http" or "socks5". When proxy is set, useProxy is not used. |
options.endpoint |
Base API address for a service that is not in the provider list, for example "https://my-llm.example.com/v1". When you use it, you must set model. baseUrl also works. |
options.kind |
API style of endpoint: "openai", "anthropic" or "gemini". If empty, it is guessed from the address; if it cannot be guessed, the openai style is assumed. |
options.headers |
Extra HTTP headers for the request, as {name: value}. |
options.body |
Object merged into the request body last, overriding fields with the same name; use it for provider-specific parameters. |
options.path |
Request path to use instead of the default, appended to the base address, for example "/chat/completions". |
Returns
Object {ok, text, json, usage, provider, model, finishReason, status, error, raw}:
ok:truewhen the call succeeds.text: the answer; an empty string on error, so always checkokfirst.json: the parsed object when you turn onjsonor when the answer looks like JSON;nullwhen there is none or it cannot be parsed. Havingjsondoes not mean the model followed the schema.usage: token counts{input, output, total};0when the provider does not report them.provider,model: the provider and model that answered.finishReason: why the model stopped, in the provider's own terms.status: the HTTP code of the last call,0when it could not connect.error: the error reason; an empty string on success.raw: the provider's original response.
Examples
GenImageAI#
Creates images from a text description. It works with gemini and OpenAI-compatible providers;
anthropic cannot create images and returns an error immediately. With gemini only prompt is
sent, and the model decides how many images come back.
Parameters
| Name | Description |
|---|---|
options.provider |
Provider, as in PromptAI. |
options.apiKey |
Your API key with that provider. |
options.model |
Image model. If empty, gpt-image-1 is used with OpenAI-compatible providers and gemini-2.5-flash-image with gemini; these differ from the chat models of PromptAI. |
options.prompt |
Description of the image to create. Required. |
options.n |
Number of images to create. Default 1. Only applies to OpenAI-compatible providers. |
options.size |
Image size. Default "1024x1024". Only applies to OpenAI-compatible providers. |
options.quality |
Image quality; the provider defines the values. Only applies to OpenAI-compatible providers. |
options.style |
Image style; the provider defines the values. Only applies to OpenAI-compatible providers. |
options.background |
Image background type; the provider defines the values. Only applies to OpenAI-compatible providers. |
options.format |
"url" (get an image link) or "b64_json" (get base64 data). Set it only when you need it, because some models return an error when they receive this field (such as gpt-image-1, which always returns base64). responseFormat also works. |
options.timeout |
Timeout for each call, in milliseconds. Default 120000, because image generation is slow; counting the retries, a failing call can take several minutes. |
options.endpoint, options.kind, options.retries, options.useProxy, options.proxy, options.headers, options.body, options.path |
Same as in PromptAI. |
Returns
Object {ok, images, provider, model, status, error, raw}:
ok:truewhen there is at least one image. A successful call with no images still returnsfalse.images: an array of{url, b64, mime, revisedPrompt}. Depending on the provider, each image hasurlorb64, so read both.mimeis the image type, for example"image/png";revisedPromptis the description as rewritten by the provider, if any.provider,model,status,error,raw: same as inPromptAI.
Examples
ListAIModels#
Lists the models that your API key can use with a provider. Call it before you hard-code a model name into a script, because each account and each key may have access to different models.
Parameters
| Name | Description |
|---|---|
options.provider |
Provider, as in PromptAI. model is not needed. |
options.apiKey |
Your API key with that provider. |
options.filter |
Keep only the models whose name contains this string, case-insensitive. |
options.timeout |
Timeout for each call, in milliseconds. Default 30000. |
options.endpoint, options.kind, options.retries, options.useProxy, options.proxy, options.headers |
Same as in PromptAI. |
Returns
Object {ok, ids, models, provider, status, error, raw}:
ids: an array of model names in alphabetical order, ready to use asmodelforPromptAI.models: an array of{id, name, created}, wherenameis the display name andcreatedis the creation time reported by the provider (0if there is none).ok,provider,status,error,raw: same as inPromptAI.
An endpoint that does not support listing models returns ok: false, not an empty list.