GeeTest v4 Image Solving
Solve GeeTest v4 captcha challenges including slide puzzles, icon crush, gobang, click, and grid (nine) challenges. GeeTest v4 is the latest version with enhanced security features.
GeeTest v4 is an advanced anti-bot system that presents users with various interactive challenges. It includes slide puzzles, icon matching games, and other visual challenges that require image analysis and pattern recognition. Our API handles all GeeTest v4 challenge types with high accuracy.
Captcha Type
Use the following captcha type identifier in your API requests:
"type": "GEETEST_V4_IMAGE"
Challenge Types
| Type | Description |
|---|---|
| slide | Slide puzzle piece to complete image |
| icon / iconcrush | Match and eliminate icons |
| gobang | Connect-five puzzle game |
| click | Click matching icons in sequence |
| grid | 3x3 grid image selection (nine captcha) |
Request Format
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
auth.token |
string | required | Your API key |
captcha.type |
string | required | Must be "GEETEST_V4_IMAGE" |
captcha.metadata.siteUrl |
string | required | The URL where the captcha appears |
captcha.metadata.siteKey |
string | optional | GeeTest captcha ID (if available) |
captcha.payload.images |
array | required | Array of base64-encoded images |
captcha.payload.questionType |
string | required | Challenge type: "slide", "iconcrush", "gobang", "click", or "grid" |
captcha.payload.question |
string | optional | Question text (recommended for grid challenges) |
captcha.payload.referenceImages |
array | optional | Reference images (required for grid, required for click) |
Grid challenge requests must include questionType: "grid" and a single
reference image in referenceImages.
Example Request
Slide Challenge
const response = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: {
type: 'GEETEST_V4_IMAGE',
metadata: {
siteUrl: 'https://example.com',
siteKey: 'captcha_id_here'
},
payload: {
images: [
'background_image_base64',
'puzzle_piece_base64'
],
questionType: 'slide',
referenceImages: []
}
}
})
});
Icon Crush Challenge
const response = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: {
type: 'GEETEST_V4_IMAGE',
metadata: {
siteUrl: 'https://example.com'
},
payload: {
images: ['game_board_base64'],
questionType: 'iconcrush'
}
}
})
});
Click Challenge
const response = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: {
type: 'GEETEST_V4_IMAGE',
metadata: {
siteUrl: 'https://example.com'
},
payload: {
images: ['main_image_base64'],
referenceImages: [
'reference_1_base64',
'reference_2_base64',
'reference_3_base64'
],
questionType: 'click'
}
}
})
});
Grid Challenge (Nine Captcha)
const response = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: {
type: 'GEETEST_V4_IMAGE',
metadata: {
siteUrl: 'https://example.com'
},
payload: {
images: ['grid_image_base64'],
referenceImages: ['reference_image_base64'],
questionType: 'grid',
question: 'Click all images matching the reference'
}
}
})
});
Response Format
Create Task Response (Processing)
{
"success": true,
"service": "MyDisct Solver",
"message": "Captcha is being processed",
"task": {
"id": "MyDisctSolver_abc123",
"status": "processing"
}
}
Fetch Result Response (Processing)
{
"success": true,
"service": "MyDisct Solver",
"message": "Captcha is being processed",
"task": {
"id": "MyDisctSolver_abc123",
"status": "processing"
}
}
Fetch Result Response (Completed)
Slide Response
{
"success": true,
"service": "MyDisct Solver",
"task": {
"id": "MyDisctSolver_abc123",
"status": "completed",
"result": {
"answers": [145, 0],
"timestamp": "2025-11-05T12:34:56.789Z"
}
}
}
Icon Crush / Gobang Response
{
"success": true,
"service": "MyDisct Solver",
"task": {
"id": "MyDisctSolver_abc123",
"status": "completed",
"result": {
"answers": [3, 7],
"timestamp": "2025-11-05T12:34:56.789Z"
}
}
}
Array contains indices of positions to swap/click.
Click Response
{
"success": true,
"service": "MyDisct Solver",
"task": {
"id": "MyDisctSolver_abc123",
"status": "completed",
"result": {
"answers": [[120, 80], [240, 160]],
"timestamp": "2025-11-05T12:34:56.789Z"
}
}
}
Array of [x, y] coordinates to click in sequence.
Grid Response (Nine Captcha)
{
"success": true,
"service": "MyDisct Solver",
"task": {
"id": "MyDisctSolver_abc123",
"status": "completed",
"result": {
"answers": [1, 4, 7],
"timestamp": "2025-11-05T12:34:56.789Z"
}
}
}
For grid: Array of cell indices (1-9) to click in the 3x3 grid.
The answers array format depends on the challenge type:
• Slide: [x, y] coordinates for puzzle placement
• Icon/Gobang: Array of indices for swap positions
• Click: Array of [x, y] coordinates for sequential clicks
• Grid: Array of cell indices (1-9) to click in the 3x3 grid
Implementation Guide
Step 1: Extract Images from GeeTest v4
GeeTest v4 challenges vary by type. Here's how to extract data for each challenge type:
// Extract GeeTest v4 challenge data
function extractGeeTestData() {
const iframe = document.querySelector('iframe[src*="geetest.com"]');
if (!iframe) return null;
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
const challengeType = detectChallengeType(iframeDoc);
let images = [];
let referenceImages = [];
switch (challengeType) {
case 'slide':
images = extractSlideImages(iframeDoc);
break;
case 'iconcrush':
case 'gobang':
images = [extractGameBoardImage(iframeDoc)];
break;
case 'click':
images = extractClickImages(iframeDoc);
referenceImages = extractReferenceImages(iframeDoc);
break;
case 'grid':
images = extractGridImages(iframeDoc);
referenceImages = extractReferenceImages(iframeDoc);
break;
}
return { challengeType, images, referenceImages };
}
function detectChallengeType(iframeDoc) {
if (iframeDoc.querySelector('.geetest_slide')) return 'slide';
if (iframeDoc.querySelector('.geetest_iconcrush')) return 'iconcrush';
if (iframeDoc.querySelector('.geetest_gobang')) return 'gobang';
if (iframeDoc.querySelector('.geetest_click')) return 'click';
if (iframeDoc.querySelector('.geetest_nine')) return 'grid';
return 'unknown';
}
Step 2: Send to API and Poll for Result
async function solveGeeTestV4(challengeType, images, referenceImages, siteUrl, siteKey) {
const createResponse = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: {
type: 'GEETEST_V4_IMAGE',
metadata: { siteUrl, siteKey },
payload: {
images,
questionType: challengeType,
referenceImages: referenceImages || []
}
}
})
});
const createData = await createResponse.json();
if (!createData.success) {
throw new Error(createData.error.message);
}
const taskId = createData.task.id;
while (true) {
await new Promise(resolve => setTimeout(resolve, 3000));
const resultResponse = await fetch('https://solver-api.mydisct.com/fetchResult', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'YOUR_API_KEY'
},
body: JSON.stringify({ taskId })
});
const resultData = await resultResponse.json();
if (resultData.task.status === 'completed') {
return resultData.task.result.answers;
} else if (resultData.task.status === 'failed') {
throw new Error('Captcha solving failed');
}
}
}
const { challengeType, images, referenceImages } = extractGeeTestData();
const solution = await solveGeeTestV4(
challengeType,
images,
referenceImages,
'https://example.com',
'captcha_id_here'
);
console.log('Solution:', solution);
Step 3: Apply Solution to GeeTest v4
function applyGeeTestSolution(solution, challengeType) {
const iframe = document.querySelector('iframe[src*="geetest.com"]');
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
switch (challengeType) {
case 'slide':
const [x, y] = solution;
const slider = iframeDoc.querySelector('.geetest_slider');
break;
case 'iconcrush':
case 'gobang':
solution.forEach(([fromIndex, toIndex]) => {
const element1 = iframeDoc.querySelector(`[data-index="${fromIndex}"]`);
const element2 = iframeDoc.querySelector(`[data-index="${toIndex}"]`);
});
break;
case 'click':
solution.forEach(([x, y]) => {
const clickEvent = new MouseEvent('click', {
clientX: x,
clientY: y,
bubbles: true
});
iframeDoc.dispatchEvent(clickEvent);
});
break;
}
const submitBtn = iframeDoc.querySelector('.geetest_commit');
if (submitBtn) submitBtn.click();
}
applyGeeTestSolution(solution, challengeType);
Python Example
import requests
import time
def solve_geetest_v4(images, question_type, site_url, api_key,
question=None, reference_images=None):
payload = {
'images': images,
'questionType': question_type
}
if question:
payload['question'] = question
if reference_images:
payload['referenceImages'] = reference_images
create_response = requests.post(
'https://solver-api.mydisct.com/createTask',
headers={'Content-Type': 'application/json', 'apikey': api_key},
json={
'auth': {'token': api_key},
'context': {'source': 'api', 'version': '1.0.0'},
'captcha': {
'type': 'GEETEST_V4_IMAGE',
'metadata': {'siteUrl': site_url},
'payload': payload
}
}
)
create_data = create_response.json()
if not create_data['success']:
raise Exception(create_data['error']['message'])
task_id = create_data['task']['id']
while True:
time.sleep(3)
result_response = requests.post(
'https://solver-api.mydisct.com/fetchResult',
headers={'Content-Type': 'application/json', 'apikey': api_key},
json={'taskId': task_id}
)
result_data = result_response.json()
if result_data['task']['status'] == 'completed':
return result_data['task']['result']['answers']
elif result_data['task']['status'] == 'failed':
raise Exception('Captcha solving failed')
# Slide example
solution = solve_geetest_v4(
images=['background_base64', 'piece_base64'],
question_type='slide',
site_url='https://example.com',
api_key='YOUR_API_KEY'
)
print(f'Solution: {solution}')
Best Practices
- Include captcha_id (siteKey) when available for better accuracy
- For click challenges, include all 3 reference images
- For grid challenges, include a reference image and question text
- Icon crush and gobang return swap positions (0-based indices)
- Grid responses may return 1-indexed cell numbers (1-9) for a 3x3 grid
- Ensure images are properly base64 encoded
- Poll for results every 3 seconds to avoid rate limiting
Common Issues
Solution: Ensure you use one of the supported questionType values: "slide", "icon", "iconcrush", "gobang", or "click". Check that the questionType matches the actual challenge presented by GeeTest.
Solution: Click challenges require reference images to be included. Make sure to extract and send all 3 reference images shown above the clickable area.
Solution: Grid challenges require a reference image showing what to match. Include the reference image in the referenceImages array.
Solution: GeeTest frequently updates their interface. Monitor for changes in CSS selectors and update your detection logic accordingly. Consider using multiple selectors for redundancy.
Solution: Ensure coordinates are applied relative to the iframe's viewport. Use iframeDoc.elementFromPoint() or calculate absolute positions correctly.