Use these steps when your integration needs browser values or session continuity, in either mode. Prepared SDK inputs do not require a browser collector. The application example below uses headers; follow Form payload integration to compose a form body.
Use measured browser values
Run the profile collector on the source page when measured values are needed and save profile.json. Supply those values in profile; do not invent measurements or randomize them between collection and sending.
| Field | Details |
|---|---|
user_agent, platform, language, languages | Browser identity and language. |
navigator | userAgent, platform, vendor, appVersion, appCodeName, appName, product, language, languages, hardwareConcurrency, maxTouchPoints, webdriver, cookieEnabled, doNotTrack. |
screen | width, height, availWidth, availHeight, colorDepth, pixelDepth. |
window | innerWidth, innerHeight, outerWidth, outerHeight, devicePixelRatio, screenX, screenY, screenLeft, screenTop, pageXOffset, pageYOffset. |
webgl | renderer and vendor. |
canvas | Optional data_url with the actual PNG pixels required by the protection code. A hash is not a substitute. |
- Unknown fields and conflicting top-level/navigator aliases are rejected.
{}selects server defaults, not your actual browser. Check the returnedprofile_used.- The SDK’s
validate_profilechecks inputs offline. Native Android/iOS protection is outside this web Shape API.
Profile bounds
- Identity strings: 8,192 characters. Languages: 1–32 values.
- Dimensions: up to 32,768; available screen dimensions may be zero. Coordinates: signed 32-bit; pixel ratio: 0.1–16.
- Hardware concurrency: 1–1,024; touch points: 0–100; color/pixel depth: 1–64.
- Canonical profile: 64 KiB. Canvas PNG: 64 KiB, up to 8,192 pixels per dimension and 16 million total pixels.
Keep the target session consistent
- Use browser-grade target transport, such as a compatible
curl_cffiChrome impersonation. A User-Agent alone does not guarantee a matching TLS fingerprint. - When session continuity applies, keep IP continuity and browser identity from collection through the protected request. Retain a sticky proxy only if your integration uses one.
- When cookies are used, keep them in a scoped cookie jar. Supply
document_cookiefrom the source page; exclude HttpOnly values. - Match the browser’s header values and order. Keep required Origin, Referer, authentication and CSRF headers when required. Remove stale telemetry before applying the entire fresh header map with names unchanged and values intact, including optional same-family a0 when the scripts emit it.
RayonAPI does not return replacement cookies. The SDK’s connection to RayonAPI does not configure your target client. Never forward the RayonAPI key to the target. Do not forward generated headers or cookie values to unrelated hosts.
Send the exact request
Check the destination against an explicit approved HTTPS origin allowlist. Source and API subdomains may differ when both have approved access.
from urllib.parse import urlsplit
def https_origin(url):
parsed = urlsplit(url)
if (parsed.scheme != "https" or not parsed.hostname
or parsed.username is not None or parsed.password is not None
or parsed.fragment):
raise ValueError("Use HTTPS without credentials or a fragment")
port = parsed.port if parsed.port is not None else 443
if not 1 <= port <= 65535:
raise ValueError("Invalid port")
return (parsed.scheme, parsed.hostname.lower(), port)
allowed_origins = {
https_origin("https://shop.example.com"),
https_origin("https://api.shop.example.com"),
}
request = shape["request"]
if https_origin(request["url"]) not in allowed_origins:
raise ValueError("Endpoint origin not allowed")
body = request["body"]
headers = {**application_headers, **result.headers,
"User-Agent": result.profile_used["user_agent"]}
if request["content_type"] is not None:
headers["Content-Type"] = request["content_type"]
response = target_session.request(
request["method"], request["url"],
data=body.encode("utf-8") if body is not None else None,
headers=headers, allow_redirects=False, timeout=30,
)target_sessionis the session that fetched your scripts;application_headerscontains the target’s required headers, not the RayonAPI key.- Serialize JSON once. Preserve whitespace and UTF-8 bytes. Null means no body; an empty string means an empty body.
- Inspect the target body as well as its status. HTTP 200 can still contain a challenge page.
For a runnable version, use the complete Python workflow.