Was this helpful?
How to bypass MTCaptcha on Checkinhoudingsplicht
Technical engineer
The Checkinhoudingsplicht website (checkinhoudingsplicht.be) is an official Belgian government portal designed for employers. It is used to verify and confirm compliance with the duty to check the residence status of foreign workers (known as the houdingsplicht). To protect its forms from automation and bots, the site uses the MTCaptcha system.
This captcha is an interactive widget that evaluates user behavior. For a successful solution via API v2, you need to extract the public site key (sitekey) and pass it along with the full page URL. In this guide, we will break down how to find these parameters, send the task, and correctly inject the received token.
Task Parameters (API v2)
To send a task via the modern API v2, the createTask endpoint is used. The task object must contain the following parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Task type: MTCaptchaTaskProxyless or MTCaptchaTask |
| websiteURL | String | Yes | Full URL of the page where the captcha is located |
| websiteKey | String | Yes | MTCaptcha public site key (starts with MTPublic-) |
How to find parameters
Parameters for MTCaptcha are static for a specific page and can be easily extracted from the source code.
- Open the website https://www.checkinhoudingsplicht.be/ in your browser.
- Press F12 to open Developer Tools (DevTools) and go to the Elements tab.
- Press Ctrl+F (or Cmd+F) and search for mt-captcha or data-sitekey.
- You will find a div element similar to this:
- The value of the data-sitekey attribute (in this example, MTPublic-QPs1BHRjl) is your websiteKey.
- Copy the full URL from the browser's address bar. This will be your websiteURL.
Code Examples
Python + requests (API v2)
Example of sending a task and polling for the result using the requests library via API v2 endpoints.
python
import requests
import time
API_KEY = 'YOUR_API_KEY'
WEBSITE_URL = 'https://www.checkinhoudingsplicht.be/'
WEBSITE_KEY = 'MTPublic-QPs1BHRjl'
# 1. Create task via API v2
url = 'https://api.2captcha.com/createTask'
headers = {
'Content-Type': 'application/json'
}
payload = {
"clientKey": API_KEY,
"task": {
"type": "MTCaptchaTaskProxyless",
"websiteURL": WEBSITE_URL,
"websiteKey": WEBSITE_KEY
}
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result.get('errorId') == 0:
task_id = result.get('taskId')
print(f"Task created, ID: {task_id}")
# 2. Get result via API v2
res_url = 'https://api.2captcha.com/getTaskResult'
while True:
time.sleep(5) # Pause between requests
res_payload = {
"clientKey": API_KEY,
"taskId": task_id
}
res_response = requests.post(res_url, headers=headers, json=res_payload).json()
if res_response.get('errorId') == 0 and res_response.get('status') == 'ready':
print("Captcha solved successfully!")
token = res_response['solution']['token']
print(f"Token: {token}")
break
elif res_response.get('errorId') != 0:
print(f"Error: {res_response.get('errorDescription')}")
break
else:
# Status processing - task is not ready yet
continue
else:
print(f"Task creation error: {result.get('errorDescription')}")
Python + Playwright
Example of automation that dynamically extracts the sitekey from the page, sends the task via API v2, and injects the token.
python
from playwright.sync_api import sync_playwright
import requests
import time
API_KEY = 'YOUR_API_KEY'
TARGET_URL = 'https://www.checkinhoudingsplicht.be/'
def solve_mtcaptcha():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
try:
page.goto(TARGET_URL)
# Wait for the MTCaptcha widget to appear
page.wait_for_selector('.mt-captcha', timeout=10000)
# Extract sitekey from the data-sitekey attribute
site_key = page.evaluate("""
() => {
const captchaDiv = document.querySelector('.mt-captcha');
return captchaDiv ? captchaDiv.getAttribute('data-sitekey') : null;
}
""")
if not site_key:
raise Exception("Failed to find MTCaptcha sitekey on the page.")
print(f"Found sitekey: {site_key}")
# Send to API v2
api_url = 'https://api.2captcha.com/createTask'
headers = {'Content-Type': 'application/json'}
payload = {
"clientKey": API_KEY,
"task": {
"type": "MTCaptchaTaskProxyless",
"websiteURL": page.url,
"websiteKey": site_key
}
}
task_response = requests.post(api_url, headers=headers, json=payload).json()
if task_response.get('errorId') != 0:
raise Exception(f"Task creation error: {task_response.get('errorDescription')}")
task_id = task_response.get('taskId')
# Waiting for the solution via getTaskResult
res_url = 'https://api.2captcha.com/getTaskResult'
token = None
for _ in range(20):
time.sleep(5)
res = requests.post(res_url, headers=headers, json={"clientKey": API_KEY, "taskId": task_id}).json()
if res.get('status') == 'ready':
token = res['solution']['token']
break
if res.get('errorId') != 0:
print(f"API error: {res.get('errorDescription')}")
break
if token:
print(f"Token received: {token}")
# Injecting the token into the form
# MTCaptcha usually expects the token in a hidden field named mt-captcha-response
page.evaluate(f"""
let input = document.querySelector('input[name="mt-captcha-response"]');
if (!input) {{
input = document.createElement('input');
input.type = 'hidden';
input.name = 'mt-captcha-response';
document.querySelector('form')?.appendChild(input);
}}
input.value = "{token}";
// Sometimes a callback needs to be triggered if defined
if (typeof window.mtCaptchaVerified === 'function') {{
window.mtCaptchaVerified("{token}");
}}
""")
print("Token injected into DOM.")
else:
print("Failed to get token.")
except Exception as e:
print(f"Error: {e}")
finally:
# browser.close()
if __name__ == '__main__':
solve_mtcaptcha()
Alternative Solving Method
In some cases, if the standard MTCaptcha method encounters difficulties or specific protections, you can try an alternative solution using our Normal Captcha method.
If the MTCaptcha widget displays a classic text or character image to be typed, you can take a screenshot of this element using Playwright or Selenium and send it for recognition as a normal captcha. After receiving the text response, you can type it into the captcha input field using keyboard emulation.
Normal Captcha method documentation: https://2captcha.com/api-docs/normal-captcha
Common Errors and Solutions
| Error / Problem | Cause | Solution |
|---|---|---|
| ERROR_WRONG_USER_KEY | Invalid or empty API key. | Check that the key is copied correctly from the dashboard. |
| ERROR_ZERO_BALANCE | Insufficient funds in the account. | Top up your account balance. |
| ERROR_CAPTCHA_UNSOLVABLE | The captcha cannot be solved (e.g., expired or incorrect parameters). | Ensure that the websiteKey and websiteURL are copied exactly. Do not use outdated values. |
| Token not accepted by the form | Incorrect field name for injection or missing callback trigger. | Check the page source code. Make sure you are injecting the token into the mt-captcha-response field and triggering the verification function if necessary. |
Useful Links
- API testing sandbox: https://2captcha.com/setting#sandbox
- MTCaptcha API documentation: https://2captcha.com/api-docs/mtcaptcha
- Normal Captcha API documentation (alternative method): https://2captcha.com/api-docs/normal-captcha
- Python SDK on GitHub: https://github.com/2captcha/2captcha-python
- Other examples of bypassing captchas on websites: https://2captcha.com/h?category=sites