SurSolver

Imperva solver API

Capture the block page URLs and its Incapsula session, choose the correct cookie layer, and replay the result through the same proxy.

Updated

From $0.70 / 1K tasksCharged when a task is accepted

On this page

Imperva can load a Reese84 sensor, the UT.mvc bootstrap, or both. Select the task from the captured script chain, not from the site's brand name.

Expected cookie Task type Captured URL inputs
reese84 ImpervaCookie Required sensorUrl; optional utmvcUrl and iframeUrl when the page has them
___utmvc ImpervaUtmvcCookie Required scriptUrl; optional iframeUrl

Both tasks require websiteURL, userAgent, your sticky proxy and cookies from the blocked session. Neither task discovers its script URLs by fetching the protected page.

Capture the Reese84 block

Open DevTools, Network, preserve the log and request the page through the proxy that will solve and replay it. From that same block response, capture:

Field Capture from
sensorUrl The Reese84 sensor script request; the path is site-specific and a ?s=... query on it is fine
utmvcUrl Optional: the /_Incapsula_Resource?SWJIYLWA=... bootstrap request, only when the page loads one
iframeUrl Optional: the src of iframe#main-iframe, typically /_Incapsula_Resource?CWUDNSAI=...; a "Pardon Our Interruption" page has none
cookies The block response cookies, including incap_ses_* and any visid_incap_* or nlbi_* values

Resolve relative src paths against websiteURL and preserve the query strings. All URL task fields must be absolute public HTTP(S) URLs. The URLs and session cookies must come from one current block, with the same proxy exit IP and User-Agent.

A session cookie must be visible to the protection script at websiteURL. The API rejects a missing, empty, wrong-domain, wrong-path or HttpOnly-only incap_ses_* cookie before charging. Supplying an unrelated application cookie does not seed the protection session.

Reese84 request

Send this shape to POST /createTask, replacing every example value with the current capture:

snippet.json
{
  "clientKey": "sur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "task": {
    "type": "ImpervaCookie",
    "websiteURL": "https://example.com/account",
    "sensorUrl": "https://example.com/site-specific-sensor.js",
    "utmvcUrl": "https://example.com/_Incapsula_Resource?SWJIYLWA=YOUR_CAPTURE",
    "iframeUrl": "https://example.com/_Incapsula_Resource?CWUDNSAI=YOUR_CAPTURE",
    "cookies": "incap_ses_123=YOUR_SESSION; visid_incap_123=YOUR_VISITOR",
    "userAgent": "YOUR_SUPPORTED_USER_AGENT",
    "proxy": "http://user:password@proxy.example.com:8080"
  }
}

scriptUrl is not a Reese84 input. Send sensorUrl, and utmvcUrl and iframeUrl only when the captured page has them; a missing sensorUrl is rejected before a VM starts.

UTMVC request

For a page that loads only the UT.mvc bootstrap, capture its complete URL as scriptUrl. Include iframeUrl only if that page has the corresponding main iframe:

snippet.json
{
  "clientKey": "sur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "task": {
    "type": "ImpervaUtmvcCookie",
    "websiteURL": "https://example.com/account",
    "scriptUrl": "https://example.com/_Incapsula_Resource?SWJIYLWA=YOUR_CAPTURE",
    "cookies": "incap_ses_123=YOUR_SESSION; visid_incap_123=YOUR_VISITOR",
    "userAgent": "YOUR_SUPPORTED_USER_AGENT",
    "proxy": "http://user:password@proxy.example.com:8080"
  }
}

The same session-cookie requirement applies. The Reese84 API reference and UTMVC reference list their separate required fields.

Ready result and replay

Poll POST /getTaskResult with your clientKey and the returned taskId. Both task types return this shape; the cookie name comes from the selected task:

snippet.json
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "reese84": "<reese84-cookie-value>"
  }
}

This example is for ImpervaCookie. ImpervaUtmvcCookie returns ___utmvc instead of reese84. Set the named value on the protected site's domain and apply any entries in the optional cookies name-to-value object. Preserve your application's session and repeat the request through the same proxy with the task's userAgent.

A ready credential means the cookie was generated. It does not certify a 200 from the application: a site can still block the IP, require another layer or reject its own session checks. Check an application-specific success marker as well as HTTP status.

Complete solve and replay examples

Fill SENSOR_URL and SESSION_COOKIES for Reese84, plus UTMVC_URL and IFRAME_URL when the captured page has them. The script creates and polls the task, preserves that session and replaces only reese84:

imperva-python.py
# imperva-python.py - solve Imperva Reese84 and request the protected page with the reese84
# cookie.
# Install: pip install requests
# Run: python imperva-python.py

import time

import requests


# Your SurSolver API key.
CLIENT_KEY = "sur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# The challenged page, exactly as it shows the challenge.
TARGET_URL = "https://example.com/page"
# The proxy for the solve and the replay: http://user:pass@host:port or socks5://host:port.
PROXY_URL = "http://username:password@proxy.example.com:8080"
# The Reese84 sensor script URL from the current block page.
SENSOR_URL = "https://example.com/sensor.js"
# The SWJIYLWA UT.mvc bootstrap URL, when that same block page loads one.
UTMVC_URL = None
# The CWUDNSAI URL of iframe#main-iframe, when that same block page has one.
IFRAME_URL = None
# Existing session cookies as a Cookie header value (name=value; name2=value2).
SESSION_COOKIES = "incap_ses_123=YOUR_CAPTURE; visid_incap_123=YOUR_CAPTURE"
# The User-Agent the solve runs with; send the result with this same user agent.
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36"
# Text that appears only in a response the site accepted.
SUCCESS_TEXT = "PASTE_ACCEPTED_MARKER"


API = "https://api.sursolver.com"
POLL_ATTEMPTS = 60


def call(path, body):
    # API errors are HTTP 200 with errorId 1; anything else is a transport failure.
    response = requests.post(f"{API}{path}", json=body, timeout=30)
    response.raise_for_status()
    data = response.json()
    if data["errorId"] != 0:
        raise RuntimeError(f'{data["errorCode"]}: {data["errorDescription"]}')
    return data


def solve(task):
    created = call("/createTask", {"clientKey": CLIENT_KEY, "task": task})
    for _ in range(POLL_ATTEMPTS):
        result = call("/getTaskResult", {"clientKey": CLIENT_KEY, "taskId": created["taskId"]})
        if result["status"] == "ready":
            return result["solution"]
        time.sleep(3)
    raise TimeoutError(f'task {created["taskId"]} was not ready in {POLL_ATTEMPTS} polls')


def without_empty(fields):
    # Optional task fields are sent only when they have a value.
    return {name: value for name, value in fields.items() if value not in (None, "")}


PROXIES = {"http": PROXY_URL, "https": PROXY_URL}


def main():
    solution = solve({
        "type": "ImpervaCookie",
        "websiteURL": TARGET_URL,
        "sensorUrl": SENSOR_URL,
        "cookies": SESSION_COOKIES,
        "userAgent": USER_AGENT,
        **without_empty({
            "utmvcUrl": UTMVC_URL,
            "iframeUrl": IFRAME_URL,
        }),
        "proxy": PROXY_URL,
    })

    # Replay with the user agent the solve ran with, through the same proxy.
    headers = {"User-Agent": USER_AGENT}
    cookies = dict(part.strip().split("=", 1) for part in (SESSION_COOKIES or "").split(";")
                   if "=" in part)
    cookies["reese84"] = solution["reese84"]
    cookies = {
        **cookies,
        **solution.get("cookies", {}),
        "reese84": solution["reese84"],
    }
    response = requests.get(
        TARGET_URL,
        headers=headers,
        cookies=cookies,
        proxies=PROXIES,
        timeout=30,
    )
    if not response.ok or SUCCESS_TEXT not in response.text:
        raise SystemExit(f"The site did not accept the result (HTTP {response.status_code}).")
    print("The site accepted the result.")


if __name__ == "__main__":
    main()

For UTMVC, fill SCRIPT_URL and SESSION_COOKIES; supply IFRAME_URL when the captured page has one. This script replaces only ___utmvc:

imperva-utmvc-python.py
# imperva-utmvc-python.py - solve Imperva UTMVC and request the protected page with the ___utmvc
# cookie.
# Install: pip install requests
# Run: python imperva-utmvc-python.py

import time

import requests


# Your SurSolver API key.
CLIENT_KEY = "sur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# The challenged page, exactly as it shows the challenge.
TARGET_URL = "https://example.com/page"
# The proxy for the solve and the replay: http://user:pass@host:port or socks5://host:port.
PROXY_URL = "http://username:password@proxy.example.com:8080"
# The complete SWJIYLWA UT.mvc bootstrap URL from the current block page.
SCRIPT_URL = "https://example.com/challenge.js"
# The CWUDNSAI main-iframe URL when this page includes one.
IFRAME_URL = None
# Existing session cookies as a Cookie header value (name=value; name2=value2).
SESSION_COOKIES = "incap_ses_123=YOUR_CAPTURE; visid_incap_123=YOUR_CAPTURE"
# The User-Agent the solve runs with; send the result with this same user agent.
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36"
# Text that appears only in a response the site accepted.
SUCCESS_TEXT = "PASTE_ACCEPTED_MARKER"


API = "https://api.sursolver.com"
POLL_ATTEMPTS = 60


def call(path, body):
    # API errors are HTTP 200 with errorId 1; anything else is a transport failure.
    response = requests.post(f"{API}{path}", json=body, timeout=30)
    response.raise_for_status()
    data = response.json()
    if data["errorId"] != 0:
        raise RuntimeError(f'{data["errorCode"]}: {data["errorDescription"]}')
    return data


def solve(task):
    created = call("/createTask", {"clientKey": CLIENT_KEY, "task": task})
    for _ in range(POLL_ATTEMPTS):
        result = call("/getTaskResult", {"clientKey": CLIENT_KEY, "taskId": created["taskId"]})
        if result["status"] == "ready":
            return result["solution"]
        time.sleep(3)
    raise TimeoutError(f'task {created["taskId"]} was not ready in {POLL_ATTEMPTS} polls')


def without_empty(fields):
    # Optional task fields are sent only when they have a value.
    return {name: value for name, value in fields.items() if value not in (None, "")}


PROXIES = {"http": PROXY_URL, "https": PROXY_URL}


def main():
    solution = solve({
        "type": "ImpervaUtmvcCookie",
        "websiteURL": TARGET_URL,
        "scriptUrl": SCRIPT_URL,
        "cookies": SESSION_COOKIES,
        "userAgent": USER_AGENT,
        **without_empty({
            "iframeUrl": IFRAME_URL,
        }),
        "proxy": PROXY_URL,
    })

    # Replay with the user agent the solve ran with, through the same proxy.
    headers = {"User-Agent": USER_AGENT}
    cookies = dict(part.strip().split("=", 1) for part in (SESSION_COOKIES or "").split(";")
                   if "=" in part)
    cookies["___utmvc"] = solution["___utmvc"]
    cookies = {
        **cookies,
        **solution.get("cookies", {}),
        "___utmvc": solution["___utmvc"],
    }
    response = requests.get(
        TARGET_URL,
        headers=headers,
        cookies=cookies,
        proxies=PROXIES,
        timeout=30,
    )
    if not response.ok or SUCCESS_TEXT not in response.text:
        raise SystemExit(f"The site did not accept the result (HTTP {response.status_code}).")
    print("The site accepted the result.")


if __name__ == "__main__":
    main()

These scripts take SESSION_COOKIES as a Cookie header string. The API also accepts cookies as NDJSON, preserving their original host, path and visibility fields. If the site uses both layers, carry the first layer's cookies into the second solve and replay instead of replacing the entire session with one value.

Troubleshooting

Symptom Check Correction
Missing sensorUrl No sensor script URL was supplied Capture the Reese84 sensor request from the block page; add the SWJIYLWA bootstrap and CWUDNSAI iframe URLs only if that page has them
Missing UTMVC scriptUrl Discovery was assumed Supply the captured bootstrap URL
Session rejected before charging No usable incap_ses_* is visible at the page URL Capture the block cookies and preserve host, path and HttpOnly metadata
Wrong cookie is returned The two layers were confused Select the task matching the site's script chain
Ready cookie still sees a block Exit IP, session, another layer or an application policy differs Replay in the original context and inspect the protected response
Application redirects to login Authentication cookies were lost Preserve them alongside the solved cookie

The Imperva integration article explains how to distinguish the two captured script chains.

FAQ

Which inputs does Reese84 require?

ImpervaCookie requires websiteURL, userAgent, your proxy, sensorUrl and cookies containing the block response Incapsula session. Add utmvcUrl and iframeUrl only when the blocked page loads a UT.mvc bootstrap or has a main iframe. A single scriptUrl does not describe this flow.

Which inputs does UTMVC require?

ImpervaUtmvcCookie requires websiteURL, userAgent, your proxy, scriptUrl and the Incapsula session cookies. iframeUrl is optional because some UTMVC pages do not have an iframe.

Does the solver discover the scripts from websiteURL?

No. Supply the captured URLs from the current block response. Resolve relative paths against websiteURL before sending them as absolute public HTTP(S) URLs.

Which cookies must I send?

Send the block response session, including a non-empty script-visible incap_ses_* cookie for websiteURL, and keep its visid_incap_* and nlbi_* cookies when present. A different session or an HttpOnly-only cookie is insufficient for the native script.

What does a ready result contain?

ImpervaCookie returns solution.reese84; ImpervaUtmvcCookie returns solution.___utmvc. An optional solution.cookies object contains every cookie returned by the solve. Neither cookie is returned under token.