Captcha solving service blog | SolveCaptcha
How to bypass any rotate slider captcha with Python
How to bypass rotate slider captcha with Python
Rotate slider captcha asks the user to rotate an image or fragment until it reaches the correct orientation. It is commonly implemented as a circular image, puzzle fragment, or slider-controlled object that must be aligned with a reference image.
For browser automation and data collection, manually solving every rotation challenge can interrupt the entire workflow. A more practical approach is to extract the rotatable image, send it to the [SolveCaptcha API](/captcha-solver-api), receive the required rotation angle, and reproduce the movement with Selenium, Playwright, Puppeteer, or another browser automation framework.
This guide explains how to:
- identify a rotate slider captcha;
- extract the original captcha image;
- submit it to SolveCaptcha;
- poll the API for the result;
- interpret positive and negative rotation values;
- convert the returned angle into slider movement;
- apply the result with Selenium;
- handle retries, expired challenges, and API errors.
Use this method only on websites you own or are authorized to test and automate.
## What is a rotate slider captcha?
A rotate slider captcha is an image-based verification challenge where the user must rotate an object into the correct position.
Common implementations include:
- rotating an image until it becomes upright;
- aligning an inner circular fragment with an outer image;
- matching the orientation of two image layers;
- rotating a puzzle fragment to fit a target area;
- dragging a slider that controls an image’s rotation angle.
The page may display a slider below the image. Moving the slider changes the CSS transform, canvas rendering, or server-generated rotation value.
A simplified implementation may use:
```css
transform: rotate(120deg);
```
More advanced widgets may also validate:
- the final rotation angle;
- movement duration;
- intermediate slider positions;
- mouse or touch events;
- cookies and browser state;
- challenge identifiers;
- session-specific verification parameters.
The browser automation framework handles the user interaction. SolveCaptcha determines how far the image must be rotated.
## Rotate captcha and rotate slider captcha differences
The terms are often used interchangeably, but the browser interaction can differ.
### Rotate captcha
The user clicks buttons to rotate an image in fixed increments.
For example:
```text
40 degrees clockwise per click
```
A returned result of:
```text
120
```
means the script should rotate the image three times:
```text
120 / 40 = 3 clicks
```
### Rotate slider captcha
The user drags a slider that changes the angle continuously or in small increments.
For example:
```text
Slider travel: 280 pixels
Rotation range: 360 degrees
Required angle: 180 degrees
```
The required slider movement is:
```text
280 × 180 / 360 = 140 pixels
```
The SolveCaptcha result provides the rotation angle. Your browser automation code must convert that angle into the interaction expected by the target widget.
## How SolveCaptcha rotate captcha solving works
The standard workflow contains four stages:
1. Extract the image that must be rotated.
2. Submit the image to SolveCaptcha.
3. Poll the API until the answer is ready.
4. Rotate the image or move the slider according to the returned angle.
The task is submitted to:
```text
POST https://api.solvecaptcha.com/in.php
```
The result is retrieved from:
```text
GET https://api.solvecaptcha.com/res.php
```
The required API method is:
```text
rotatecaptcha
```
SolveCaptcha accepts the image as either:
- a multipart file;
- a base64-encoded image in the `body` parameter.
For browser automation, base64 is usually more convenient because images extracted from a canvas, screenshot, or network response can be sent without first saving them permanently.
## SolveCaptcha request parameters
A base64 request uses the following fields:
```text
key=YOUR_API_KEY
method=rotatecaptcha
body=BASE64_IMAGE
angle=40
json=1
```
Parameters:
| Parameter | Required | Description |
|---|---:|---|
| `key` | Yes | Your SolveCaptcha API key |
| `method` | Yes | Must be `rotatecaptcha` |
| `body` | Yes for base64 | Base64-encoded image that must be rotated |
| `file` | Yes for multipart | Image file when using multipart upload |
| `angle` | No | Rotation increment in degrees |
| `json` | No | Set to `1` to receive JSON responses |
The `angle` parameter defines the size of one rotation step.
For example:
```text
angle=40
```
means the solver returns a result based on 40-degree increments.
When the parameter is omitted, SolveCaptcha uses a default value of 40 degrees.
Use the same rotation increment as the target widget whenever possible. If the page rotates the image by 15 degrees per button click, submit:
```text
angle=15
```
## Create a rotate captcha task
Example request:
```bash
curl --request POST \
--url https://api.solvecaptcha.com/in.php \
--data-urlencode "key=YOUR_API_KEY" \
--data-urlencode "method=rotatecaptcha" \
--data-urlencode "body=BASE64_IMAGE" \
--data-urlencode "angle=40" \
--data-urlencode "json=1"
```
A successful response contains the captcha task ID:
```json
{
"status": 1,
"request": "2122988149"
}
```
Save the `request` value. It is required to retrieve the result.
## Get the rotation result
Wait approximately five seconds before requesting the result:
```bash
curl "https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=get&id=2122988149&json=1"
```
If the task is still being processed, the API returns:
```json
{
"status": 0,
"request": "CAPCHA_NOT_READY"
}
```
Wait another five seconds and repeat the request using the same task ID.
When the task is complete, the response may look like:
```json
{
"status": 1,
"request": "120"
}
```
The returned value is the required rotation angle.
For several submitted images, the response can contain multiple values:
```text
40|200|-120
```
Each value corresponds to an image in the same order in which the images were submitted.
## Clockwise and counterclockwise rotation
SolveCaptcha uses signed angle values:
- a positive value means clockwise rotation;
- a negative value means counterclockwise rotation.
Examples:
```text
120
```
Rotate the image 120 degrees clockwise.
```text
-80
```
Rotate the image 80 degrees counterclockwise.
When the target widget supports rotation in only one direction, normalize negative values into the equivalent positive angle.
Example:
```text
-80 degrees = 280 degrees clockwise
```
Python conversion:
```python
clockwise_angle = returned_angle % 360
```
Examples:
```python
120 % 360 # 120
-80 % 360 # 280
-120 % 360 # 240
```
Do not normalize the value when the interface supports both clockwise and counterclockwise controls and using the shorter direction is more appropriate.
## Complete Python client for SolveCaptcha
Install Requests:
```bash
python -m pip install requests
```
Set the API key.
Linux or macOS:
```bash
export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
```
Windows PowerShell:
```powershell
$env:SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
```
Create `solve_rotate_captcha.py`:
```python
#!/usr/bin/env python3
import argparse
import base64
import os
import time
from pathlib import Path
from typing import Any
import requests
CREATE_TASK_URL = "https://api.solvecaptcha.com/in.php"
GET_RESULT_URL = "https://api.solvecaptcha.com/res.php"
class SolveCaptchaError(RuntimeError):
"""Raised when the SolveCaptcha API returns an error."""
def parse_json_response(response: requests.Response) -> dict[str, Any]:
response.raise_for_status()
try:
data = response.json()
except requests.JSONDecodeError as exc:
raise SolveCaptchaError(
f"SolveCaptcha returned invalid JSON: {response.text[:500]}"
) from exc
if not isinstance(data, dict):
raise SolveCaptchaError(
f"Unexpected SolveCaptcha response: {data!r}"
)
return data
def parse_rotation_angles(answer: str) -> list[float]:
normalized = answer.strip()
if normalized.startswith("OK|"):
normalized = normalized[3:]
if not normalized:
raise SolveCaptchaError("SolveCaptcha returned an empty answer")
angles: list[float] = []
for raw_value in normalized.split("|"):
value = raw_value.strip()
if not value:
continue
try:
angles.append(float(value))
except ValueError as exc:
raise SolveCaptchaError(
f"Unexpected rotation value: {value!r}"
) from exc
if not angles:
raise SolveCaptchaError(
f"No rotation angles found in answer: {answer!r}"
)
return angles
class SolveCaptchaRotateClient:
def __init__(
self,
api_key: str,
poll_interval: float = 5.0,
request_timeout: float = 30.0,
) -> None:
if not api_key:
raise ValueError("SolveCaptcha API key is required")
self.api_key = api_key
self.poll_interval = poll_interval
self.request_timeout = request_timeout
self.session = requests.Session()
def create_task(
self,
image_bytes: bytes,
angle_step: int = 40,
) -> str:
if not image_bytes:
raise ValueError("Captcha image is empty")
if angle_step <= 0:
raise ValueError(
"Rotation angle step must be greater than zero"
)
encoded_image = base64.b64encode(image_bytes).decode("ascii")
payload = {
"key": self.api_key,
"method": "rotatecaptcha",
"body": encoded_image,
"angle": angle_step,
"json": 1,
}
response = self.session.post(
CREATE_TASK_URL,
data=payload,
timeout=self.request_timeout,
)
data = parse_json_response(response)
if data.get("status") != 1:
error_code = str(
data.get("request", "UNKNOWN_ERROR")
)
raise SolveCaptchaError(
f"Unable to create rotate captcha task: "
f"{error_code}"
)
task_id = str(data.get("request", "")).strip()
if not task_id:
raise SolveCaptchaError(
"SolveCaptcha did not return a task ID"
)
return task_id
def get_result(
self,
task_id: str,
) -> list[float] | None:
params = {
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1,
}
response = self.session.get(
GET_RESULT_URL,
params=params,
timeout=self.request_timeout,
)
data = parse_json_response(response)
if data.get("status") == 1:
return parse_rotation_angles(
str(data.get("request", ""))
)
error_code = str(
data.get("request", "UNKNOWN_ERROR")
)
if error_code == "CAPCHA_NOT_READY":
return None
raise SolveCaptchaError(
f"Rotate captcha task {task_id} failed: "
f"{error_code}"
)
def solve(
self,
image_bytes: bytes,
angle_step: int = 40,
max_wait: float = 180.0,
) -> tuple[str, list[float]]:
task_id = self.create_task(
image_bytes=image_bytes,
angle_step=angle_step,
)
deadline = time.monotonic() + max_wait
while time.monotonic() < deadline:
time.sleep(self.poll_interval)
result = self.get_result(task_id)
if result is not None:
return task_id, result
raise TimeoutError(
f"SolveCaptcha task {task_id} was not completed "
f"within {max_wait:.0f} seconds"
)
def report(
self,
task_id: str,
accepted: bool,
) -> None:
params = {
"key": self.api_key,
"action": (
"reportgood"
if accepted
else "reportbad"
),
"id": task_id,
"json": 1,
}
response = self.session.get(
GET_RESULT_URL,
params=params,
timeout=self.request_timeout,
)
parse_json_response(response)
def main() -> None:
parser = argparse.ArgumentParser(
description=(
"Solve a rotate captcha through SolveCaptcha."
)
)
parser.add_argument(
"image",
type=Path,
help="Path to the image that must be rotated",
)
parser.add_argument(
"--angle-step",
type=int,
default=40,
help="Rotation increment used by the captcha",
)
parser.add_argument(
"--max-wait",
type=float,
default=180.0,
help="Maximum result wait time in seconds",
)
args = parser.parse_args()
api_key = os.environ.get(
"SOLVECAPTCHA_API_KEY",
"",
).strip()
if not api_key:
raise SystemExit(
"Set the SOLVECAPTCHA_API_KEY "
"environment variable"
)
if not args.image.is_file():
raise SystemExit(
f"Image file does not exist: {args.image}"
)
client = SolveCaptchaRotateClient(
api_key=api_key
)
task_id, angles = client.solve(
image_bytes=args.image.read_bytes(),
angle_step=args.angle_step,
max_wait=args.max_wait,
)
print(f"Task ID: {task_id}")
for index, angle in enumerate(angles, start=1):
direction = (
"clockwise"
if angle >= 0
else "counterclockwise"
)
print(
f"Image {index}: "
f"{abs(angle):g} degrees {direction}"
)
if __name__ == "__main__":
main()
```
Run the script:
```bash
python solve_rotate_captcha.py rotate-captcha.png
```
Specify a different rotation increment:
```bash
python solve_rotate_captcha.py rotate-captcha.png \
--angle-step 15
```
Example output:
```text
Task ID: 2122988149
Image 1: 120 degrees clockwise
```
## How to extract a rotate captcha image
The correct image must be submitted to SolveCaptcha.
Avoid sending:
- a full browser screenshot;
- the slider track;
- page text;
- buttons;
- borders around the captcha;
- unrelated interface elements.
Send only the image that must be rotated.
The extraction method depends on how the widget renders the image.
## Extract an img element with Selenium
If the captcha uses an `
` element, Selenium can take a screenshot of that specific element:
```python
from selenium.webdriver.common.by import By
captcha_image = driver.find_element(
By.CSS_SELECTOR,
".rotate-captcha img"
)
image_bytes = captcha_image.screenshot_as_png
```
The returned PNG bytes can be passed directly to the Python client:
```python
task_id, angles = client.solve(
image_bytes=image_bytes,
angle_step=40,
)
```
This approach captures only the rendered image and avoids including unrelated page elements.
## Extract a canvas image
Some rotate captcha widgets use an HTML canvas.
Try extracting the original canvas pixels:
```python
import base64
data_url = driver.execute_script("""
const canvas = document.querySelector(
'.rotate-captcha canvas'
);
if (!canvas) {
throw new Error('Captcha canvas not found');
}
return canvas.toDataURL('image/png');
""")
encoded = data_url.split(",", 1)[1]
image_bytes = base64.b64decode(encoded)
```
Canvas extraction may fail when a cross-origin image has made the canvas unreadable.
In that case, use an element screenshot:
```python
canvas = driver.find_element(
By.CSS_SELECTOR,
".rotate-captcha canvas"
)
image_bytes = canvas.screenshot_as_png
```
## Extract an image from a CSS background
A captcha may use a CSS background instead of an `
` element.
Example:
```html
```
A simple option is to capture the element:
```python
element = driver.find_element(
By.CSS_SELECTOR,
".rotate-image"
)
image_bytes = element.screenshot_as_png
```
When possible, inspect the Network panel and download the original image URL. Original image files usually produce more accurate results than resized browser screenshots.
## Preserve the original image dimensions
The submitted image should not be:
- stretched;
- compressed excessively;
- partially cropped;
- rotated before submission;
- covered by another element.
If the image is rendered at a different size from the original file, you can still submit an element screenshot, but account for scaling when applying the result to the browser.
For example:
```text
Original image width: 323 px
Rendered image width: 258.4 px
Scale factor: 258.4 / 323 = 0.8
```
The rotation angle itself does not change with image scaling, but slider dimensions and mouse offsets do.
## Apply the angle using rotation buttons
Some widgets use clockwise and counterclockwise buttons.
Suppose SolveCaptcha returns:
```text
120
```
And each click rotates the image by:
```text
40 degrees
```
The required number of clicks is:
```text
120 / 40 = 3
```
Selenium example:
```python
from selenium.webdriver.common.by import By
def apply_rotation_with_buttons(
driver,
angle: float,
angle_step: int,
) -> None:
clockwise_button = driver.find_element(
By.CSS_SELECTOR,
".rotate-clockwise"
)
counterclockwise_button = driver.find_element(
By.CSS_SELECTOR,
".rotate-counterclockwise"
)
click_count = round(
abs(angle) / angle_step
)
button = (
clockwise_button
if angle >= 0
else counterclockwise_button
)
for _ in range(click_count):
button.click()
```
Call it with:
```python
apply_rotation_with_buttons(
driver=driver,
angle=angles[0],
angle_step=40,
)
```
Use the same `angle_step` value in both the SolveCaptcha request and browser interaction.
## Convert the angle into slider movement
For a slider-controlled widget, convert degrees into pixels.
The general formula is:
```text
offset =
usable slider width
× returned angle
÷ total rotation range
```
For example:
```text
Usable slider width: 280 px
Rotation range: 360 degrees
Returned angle: 180 degrees
```
Result:
```text
280 × 180 / 360 = 140 px
```
The usable slider width is usually:
```text
track width - handle width
```
Python function:
```python
def angle_to_slider_offset(
angle: float,
usable_width: float,
rotation_range: float = 360.0,
) -> float:
normalized_angle = angle % rotation_range
return (
usable_width
* normalized_angle
/ rotation_range
)
```
Example:
```python
offset = angle_to_slider_offset(
angle=180,
usable_width=280,
)
print(offset) # 140.0
```
## Move the rotate slider with Selenium
The following example assumes:
- the slider starts at zero degrees;
- the complete slider range represents 360 degrees;
- the handle initially starts at the left edge;
- the widget accepts mouse drag events.
```python
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
def move_rotate_slider(
driver,
angle: float,
) -> None:
track = driver.find_element(
By.CSS_SELECTOR,
".rotate-slider-track"
)
handle = driver.find_element(
By.CSS_SELECTOR,
".rotate-slider-handle"
)
track_width = track.rect["width"]
handle_width = handle.rect["width"]
usable_width = (
track_width - handle_width
)
normalized_angle = angle % 360
offset = (
usable_width
* normalized_angle
/ 360
)
actions = ActionChains(driver)
actions.move_to_element(handle)
actions.click_and_hold()
actions.pause(0.1)
actions.move_by_offset(
offset * 0.35,
1,
)
actions.pause(0.05)
actions.move_by_offset(
offset * 0.40,
-1,
)
actions.pause(0.05)
actions.move_by_offset(
offset * 0.25,
0,
)
actions.pause(0.1)
actions.release()
actions.perform()
```
Use it after receiving the result:
```python
task_id, angles = client.solve(
image_bytes=image_bytes,
angle_step=40,
)
move_rotate_slider(
driver=driver,
angle=angles[0],
)
```
The selectors and angle-to-pixel mapping must be adapted to the target website.
## Widgets with a limited rotation range
Not every slider represents a full 360-degree rotation.
A widget may use:
```text
Minimum angle: -180 degrees
Maximum angle: 180 degrees
```
Or:
```text
Minimum angle: 0 degrees
Maximum angle: 270 degrees
```
Use the actual range when calculating the position.
Example:
```python
def map_angle_to_slider(
angle: float,
minimum_angle: float,
maximum_angle: float,
usable_width: float,
) -> float:
angle_range = (
maximum_angle - minimum_angle
)
if angle_range <= 0:
raise ValueError(
"Invalid rotation range"
)
clamped_angle = max(
minimum_angle,
min(maximum_angle, angle),
)
ratio = (
clamped_angle - minimum_angle
) / angle_range
return usable_width * ratio
```
Example:
```python
offset = map_angle_to_slider(
angle=90,
minimum_angle=-180,
maximum_angle=180,
usable_width=280,
)
```
Inspect the page’s JavaScript, slider attributes, or network requests to determine the actual angle range.
## How to find the slider-to-angle mapping
Use browser developer tools to inspect the widget.
Search the page scripts for:
```text
rotate
```
```text
angle
```
```text
degree
```
```text
transform
```
```text
slider
```
```text
max
```
```text
step
```
You may find values such as:
```javascript
const maxRotation = 360;
const rotationStep = 2;
```
Or an input element:
```html
```
In this case, the mapping is direct:
```text
slider value = angle
```
Another implementation may use:
```html
```
And convert the value internally:
```javascript
angle = sliderValue * 3.6;
```
For a returned angle of 180 degrees:
```text
slider value = 180 / 3.6 = 50
```
Do not assume that slider pixels, input values, and rotation degrees are identical.
## Set a range input directly
Some basic rotate captcha widgets use a native range input.
Example:
```html
```
For testing an application you control, the value can be assigned and the expected events dispatched:
```python
driver.execute_script("""
const slider = arguments[0];
const angle = arguments[1];
slider.value = angle;
slider.dispatchEvent(
new Event('input', {
bubbles: true
})
);
slider.dispatchEvent(
new Event('change', {
bubbles: true
})
);
""", slider_element, normalized_angle)
```
Some third-party widgets ignore synthetic events or require real pointer movement. In that case, use Selenium `ActionChains`.
## Wait for verification correctly
After applying the rotation, determine whether the challenge was accepted.
Possible success indicators include:
- the captcha dialog disappears;
- a success icon appears;
- the form submit button becomes enabled;
- a hidden field receives a token;
- an XHR verification request succeeds;
- the page navigates;
- the widget receives a success class.
Example:
```python
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
wait = WebDriverWait(driver, 10)
wait.until(
EC.presence_of_element_located(
(
By.CSS_SELECTOR,
".rotate-captcha-success",
)
)
)
```
Do not treat the absence of navigation as an automatic failure. Many captcha widgets verify the answer without reloading the page.
## Report correct and incorrect answers
When the returned rotation is accepted, report it as correct:
```text
action=reportgood
```
When the returned angle itself is incorrect, report it as incorrect:
```text
action=reportbad
```
Example:
```python
client.report(
task_id=task_id,
accepted=True,
)
```
Do not send `reportbad` when the failure was caused by:
- an expired challenge;
- an incorrect selector;
- a wrong slider-width calculation;
- using the wrong rotation range;
- submitting a cropped image;
- moving the wrong slider handle;
- failing to dispatch the required events;
- session or proxy problems.
Only report an incorrect result when the returned angle was genuinely wrong.
## Handle CAPCHA_NOT_READY
`CAPCHA_NOT_READY` means the task is still being processed.
Correct behavior:
1. Keep the same task ID.
2. Wait five seconds.
3. Request the result again.
4. Stop after a defined timeout.
Incorrect behavior:
- creating a duplicate task;
- polling continuously without a delay;
- treating the response as a failed solution.
## Handle ERROR_CAPTCHA_UNSOLVABLE
This error means SolveCaptcha could not determine a reliable orientation.
Possible reasons include:
- the image is too small;
- the image is blurred;
- the image contains the slider interface instead of the rotatable object;
- the captcha changed while it was being captured;
- the wrong image layer was submitted;
- the image is already transformed;
- the rotation increment does not match the challenge.
Recommended action:
1. Reload the captcha.
2. Extract a fresh image.
3. Confirm the correct image dimensions.
4. Create a new task.
5. Limit the number of retries.
Do not repeatedly submit the same unsolvable image.
## Other API errors
### ERROR_WRONG_USER_KEY
The API key is invalid.
Verify:
```text
SOLVECAPTCHA_API_KEY
```
### ERROR_ZERO_BALANCE
The account balance is insufficient.
Stop creating tasks until the balance is replenished.
### ERROR_NO_SLOT_AVAILABLE
The task cannot currently be accepted.
Use delayed retries or exponential backoff.
### Invalid JSON response
Temporary server or proxy responses may contain HTML instead of JSON.
Your API client should:
- check the HTTP status;
- handle JSON parsing errors;
- log the response body;
- retry temporary server errors;
- limit the total number of retries.
## Keep the image and result synchronized
A rotation result is valid only for the exact image submitted to SolveCaptcha.
The challenge may refresh when:
- the page reloads;
- the captcha times out;
- an incorrect answer is submitted;
- the user clicks a reload button;
- the browser session changes;
- a verification request fails.
Before applying the result, confirm that the captcha image is still the same.
One method is to calculate an image hash:
```python
import hashlib
def image_hash(image_bytes: bytes) -> str:
return hashlib.sha256(
image_bytes
).hexdigest()
```
Store the hash when creating the task:
```python
submitted_hash = image_hash(
image_bytes
)
```
Before using the result, capture the current image again:
```python
current_hash = image_hash(
current_image_bytes
)
if current_hash != submitted_hash:
raise RuntimeError(
"Rotate captcha changed before "
"the answer was applied"
)
```
Discard answers for expired or replaced images.
## Multiple rotatable images
SolveCaptcha can return several rotation values:
```text
40|200|-120
```
The values correspond to the submitted images in order:
```text
Image 1: 40 degrees clockwise
Image 2: 200 degrees clockwise
Image 3: 120 degrees counterclockwise
```
Preserve the original image order when creating the task and applying the results.
Example mapping:
```python
for element, angle in zip(
image_elements,
angles,
strict=True,
):
apply_angle(
driver,
element,
angle,
)
```
Do not sort the images or angles after receiving the response.
## Common implementation mistakes
### Sending the complete captcha screenshot
The solver needs the image that must be rotated, not the complete page or captcha interface.
### Using the wrong angle step
The `angle` request parameter should match the widget’s rotation increment.
### Ignoring negative values
Negative values indicate counterclockwise rotation.
### Assuming every slider represents 360 degrees
Inspect the widget’s actual minimum and maximum values.
### Applying the answer after the captcha refreshes
The result belongs only to the submitted image.
### Using the image width as the slider width
The slider track and captcha image can have different dimensions.
### Reporting integration errors as bad answers
Use `reportbad` only when the returned angle is wrong.
### Hardcoding selectors throughout the scraper
Keep captcha selectors in one class or configuration object so that page changes can be handled quickly.
## Recommended architecture
Keep the integration separated into clear components:
```text
RotateCaptchaExtractor
Extracts the image and challenge metadata
SolveCaptchaRotateClient
Creates tasks and retrieves angles
RotateSliderController
Converts angles into clicks or slider movement
RotateCaptchaVerifier
Checks whether the answer was accepted
```
This structure makes it easier to:
- replace Selenium with Playwright or Puppeteer;
- support several rotate captcha implementations;
- update page selectors;
- add logging and retries;
- test API logic separately from browser logic.
## Frequently asked questions
### What does SolveCaptcha return for rotate captcha?
It returns the angle required to rotate each submitted image.
Example:
```text
120
```
Or several angles:
```text
40|200|-120
```
### What does a negative angle mean?
A negative value means the image should be rotated counterclockwise.
### Which API method should I use?
Use:
```text
method=rotatecaptcha
```
### Which endpoints are required?
Create the task:
```text
https://api.solvecaptcha.com/in.php
```
Retrieve the result:
```text
https://api.solvecaptcha.com/res.php
```
### Can I submit a base64 image?
Yes. Put the base64-encoded image in the `body` parameter.
### What is the default rotation step?
The default `angle` value is 40 degrees.
Set a different value when the widget uses another rotation increment.
### Can Selenium rotate the image directly?
Selenium can modify CSS transforms, click rotation buttons, change a range input, or drag a slider.
The correct method depends on how the website validates the interaction.
### How do I convert degrees into pixels?
Use:
```text
offset =
usable slider width
× angle
÷ rotation range
```
### Why is the returned angle correct but verification fails?
Possible causes include:
- incorrect clockwise or counterclockwise handling;
- wrong slider mapping;
- incorrect rotation range;
- stale challenge image;
- missing mouse events;
- session-specific verification;
- a wrong image layer;
- premature slider release.
## Conclusion
Automatic rotate slider captcha solving requires two separate components:
1. SolveCaptcha determines the required rotation angle.
2. Selenium, Playwright, Puppeteer, or another browser framework applies that angle through the target widget.
A reliable workflow should:
1. capture only the rotatable image;
2. preserve the original dimensions and orientation;
3. submit it with `method=rotatecaptcha`;
4. specify the widget’s rotation increment through `angle`;
5. poll `res.php` every five seconds;
6. interpret positive and negative values correctly;
7. convert the angle into clicks, slider values, or mouse movement;
8. verify the real success state;
9. report accepted and incorrect answers accurately;
10. discard results when the captcha image changes.
Use the [SolveCaptcha rotate captcha API](/captcha-solver-api#solving_rotatecaptcha) to integrate automatic rotation recognition into authorized browser automation and data collection workflows.