How to Set Up Proxies in Splash in 2026 - Stepwise Guide
TL;DR
Splash routes proxies through one HTTP parameter, proxy, which accepts either a proxy URL or a named profile. The URL format is [protocol://][user:password@]host[:port], with http or socks5 as the protocol and port 1080 as the default when omitted.
Named proxy profiles require starting Splash with --proxy-profiles-path and pointing it at a folder of .ini files; a default.ini profile auto-applies to every request unless the request explicitly passes proxy=none.
Each profile's [proxy] section holds host, port, optional username/password, and type (HTTP or SOCKS5), while its [rules] section restricts the proxy to matching URLs via allowlist/denylist regex patterns.
For per-request or per-resource proxy logic, Splash's Lua API exposes inside a callback, which runs before the request is sent and can assign a different proxy to different resource types on the same page.
scrapy-splash forwards Splash's HTTP parameters unchanged, so a SplashRequest's args dictionary can carry proxy the same way a raw render.html call does.
A rotating proxy provider such as Nstproxy plugs into any of the three methods above — direct URL, profile .ini, or Lua set_proxy — because Splash treats the proxy as ordinary host:port plus optional credentials, regardless of who issues them.
Introduction: routing traffic through Splash without losing the plot
Splash is Scrapinghub/Zyte's headless, scriptable browser rendering service, most commonly reached through its HTTP API or through the scrapy-splash Scrapy integration. It renders JavaScript-heavy pages and returns HTML, PNG, JSON, or HAR, but by default every render request leaves the Splash host on Splash's own outbound IP. Sites that fingerprint by IP, block by ASN, or rate-limit by source address will treat every request the same way, no matter how many different target pages a scraper visits — until a proxy sits between Splash and the target site.
Splash exposes three separate ways to insert that proxy: a single proxy request parameter for one-off or manually rotated proxies, a --proxy-profiles-path folder of .ini files for reusable named profiles, and a Lua request:set_proxy call for per-request or per-resource-type control. This guide walks through all three, plus the scrapy-splash wiring needed to pass a proxy value from a Scrapy spider, and closes with how to plug a rotating residential proxy pool into any of the three methods.
Prerequisites
A running Splash instance — the examples below use the official scrapinghub/splash Docker image, since Splash's own install docs recommend Docker over a local Python install for most setups. Splash's source and issue tracker live in the scrapinghub/splash repository on GitHub.
Docker installed locally (or a remote host you can reach on port 8050).
Proxy credentials from a provider — host, port, and (if required) username/password. Real credentials are never printed in this article; every example uses placeholders such as YOUR_PROXY_HOST and YOUR_PROXY_PASSWORD.
scrapy and scrapy-splash installed (pip install scrapy scrapy-splash) only for the sections that use Scrapy.
None of the commands below were executed against a live Splash container in the environment that produced this article — no Docker runtime was available. Every command and parameter name is checked against Splash's own documentation and source (splash.readthedocs.io, github.com/scrapinghub/splash) rather than invented, and each code block is labeled illustrative or config-only below.
Install and start Splash
Start Splash the way its own documentation recommends, mapping the API port to the host. This command matches the documented syntax; it was not executed live in this environment (no Docker runtime available), so treat it as illustrative:
docker run -it-p8050:8050 --rm scrapinghub/splash
The API becomes reachable at http://localhost:8050. Confirm it responds before wiring in a proxy:
Once Splash can reach a target site directly, the next failure mode is usually the target site blocking Splash's own IP — a rotating residential pool like Nstproxy's Residential Lite proxies gives Splash a fresh outbound IP per session instead of one static address every site can flag.
Configure a proxy with the proxy request parameter
The fastest way to route a single render call through a proxy is Splash's proxy request argument, available on render.html, render.png, render.json, execute, and the other render endpoints. It accepts a proxy URL in the form [protocol://][user:password@]proxyhost[:port], where the protocol is http or socks5 and the port defaults to 1080 if left out:
This is the right tool when a script assembles the proxy URL at request time — for example, pulling a fresh rotating-session endpoint from a provider before each Splash call. It is not the right tool when the same proxy needs to apply automatically to every request without repeating the URL each time; that's what proxy profiles handle.
Configure reusable proxy profiles with .ini files
A proxy profile is a named .ini file that Splash reads once at startup and then reuses by name instead of a full URL. Enable profiles by starting Splash with --proxy-profiles-path pointed at a folder:
host and port are required; username, password, and type are optional (type defaults to HTTP, and Splash also accepts SOCKS5). The [rules] section's allowlist and denylist are newline-separated regular expressions: a request is proxied only when its URL matches the allowlist and does not match the denylist, so the example above proxies everything except common static-asset extensions.
Save the file as default.ini inside the profiles folder to have it apply automatically to every request without naming it, or save it under another name and reference it explicitly:
Pass proxy=none on any individual request to skip a default.ini profile when one is configured. This distinction — a default.ini that's silently active versus a profile you must name — is the single most common source of "my proxy isn't being used" reports against Splash: the request either matched a denylist rule, or a default.ini is overriding an assumption that no proxy was set at all.
Control proxies per request with the Lua scripting API
Splash's Lua scripting endpoint (execute) can inspect and modify a request before it's sent, using the splash:on_request callback and the request object's set_proxy method:
This Lua script is illustrative — matched against the documented request-object API, not executed against a live Splash instance:
functionmain(splash, args) splash:on_request(function(request)if request.url:find("%.png$")or request.url:find("%.jpg$")then request.abort()returnend request:set_proxy{ host ="YOUR_PROXY_HOST", port =tonumber("YOUR_PROXY_PORT"), username ="YOUR_PROXY_USER", password ="YOUR_PROXY_PASSWORD", type ="HTTP",}end)assert(splash:go(args.url))assert(splash:wait(0.5))return splash:html()end
set_proxy only works inside splash:on_request, and only before the request has actually been sent — calling it later in the callback has no effect. Omit username and password for a proxy that doesn't require authentication. Setting type = "HTTP" still proxies HTTPS targets correctly, since Splash implements that case with the standard CONNECT method rather than requiring a separate HTTPS proxy type.
This callback fires once per resource, not once per page, so a script can route the main document through one proxy and skip proxying (or use a different proxy) for images, fonts, or analytics beacons on the same page — something neither the proxy parameter nor a static profile can do on their own, since both apply at the level of a single render call.
Send the script to the execute endpoint with the Lua source as the lua_source parameter:
scrapy-splash sends Scrapy requests to a Splash instance and forwards the args dictionary directly as Splash's own request parameters, so a proxy key inside args behaves exactly like the proxy query-string parameter used earlier. The package's README documents the exact middleware and settings names below.
Install and wire the middlewares Scrapy needs to route requests through Splash:
pip install scrapy scrapy-splash
This settings.py snippet is config-only, matching scrapy-splash's documented README values:
This spider example is a prerequisite-gap — it was not executed against a live Splash+Scrapy stack in this environment, since no Docker/network runtime was available:
from scrapy import Spider
from scrapy_splash import SplashRequest
classProxyExampleSpider(Spider): name ="proxy_example"defstart_requests(self):yield SplashRequest( url="https://example.com/", callback=self.parse, args={"proxy":"http://YOUR_PROXY_USER:YOUR_PROXY_PASSWORD@YOUR_PROXY_HOST:YOUR_PROXY_PORT","wait":0.5,}, endpoint="render.html",)defparse(self, response):yield{"title": response.css("title::text").get()}
args values map one-to-one onto Splash's HTTP API parameters, so a named proxy profile works the same way: args={"proxy": "myprovider"}. Because SplashDeduplicateArgsMiddleware fingerprints requests by their Splash arguments, rotating the proxy value on every request (rather than reusing one static value) also prevents Scrapy's deduplication layer from treating rotated-proxy requests as duplicates of each other.
Route a rotating proxy provider through Splash
All three Splash mechanisms above expect the same three or four facts about a proxy: a host, a port, and — for authenticated pools — a username and password. A rotating residential or datacenter proxy provider supplies exactly those facts, typically through one shared gateway host and port that rotates the exit IP per session or per request behind the scenes, so none of Splash's proxy handling has to change to use one.
Nstproxy provides HTTP(S)- and SOCKS5-compatible proxy gateways across several product lines, including Residential Lite Proxies, which cover 50M+ residential IPs across 200+ countries and regions on a prepaid-package billing model. Gateway host, port, and credential details for an active plan are available from the Nstproxy documentation after signup. Because Splash only needs standard host:port plus optional user:pass credentials, a Residential Lite gateway endpoint drops into any of the patterns above — the proxy= URL parameter for one-off calls, a profile .ini's [proxy] section for a fixed default, or request:set_proxy in Lua for per-resource routing:
Session control — Nstproxy's gateway typically exposes sticky and rotating session modes through the username string itself, which matters for Splash because a profile .ini or a Lua set_proxy call is fixed for the life of the file or script; rotation then happens on the provider's side per new session rather than by editing Splash's configuration.
Protocol match — Splash's type field only recognizes HTTP and SOCKS5; confirm which protocol a given Nstproxy product line's gateway expects before writing a profile, since mismatching the type value against the actual gateway protocol produces connection failures that look like proxy failures.
Scale without touching Splash config — because the credentials live in one gateway host and port rather than a list of individual proxy IPs, scaling from one Splash worker to many doesn't require distributing or rotating a list of proxy servers across those workers.
Take a Quick Look
Splash's Lua and profile-based proxy controls only route traffic — they don't rotate IPs on their own, so pairing Splash with Nstproxy's residential gateway is what actually spreads render requests across different exit IPs over time.
A misconfigured proxy in Splash rarely errors out loudly — it just silently falls back to Splash's own IP or blocks a legitimate request, which is the recurring complaint pattern behind several open issues in the scrapinghub/splash GitHub repository. Work through these checks in order:
Check for a silent default.ini. If a default.ini file exists in the proxy-profiles folder, it applies to every request automatically; a request that's supposed to bypass a proxy needs an explicit proxy=none.
Check allowlist/denylist matches. A profile's [rules] section only proxies URLs matching the allowlist and not matching the denylist — a target URL that fails either test is fetched without the proxy, with no error raised.
Confirm the type matches the gateway's actual protocol. Requesting an HTTP proxy against a SOCKS5-only gateway (or the reverse) produces a connection failure, not a clear "wrong protocol" message.
Remember set_proxy timing. It only has an effect when called inside splash:on_request, before the request is sent; calling it anywhere else in a Lua script is silently ineffective.
Check that Splash was actually started with --proxy-profiles-path. Without that flag, named profiles aren't loaded at all, and a proxy=myprovider parameter has nothing to resolve to.
Honest limits
Splash's proxy support operates purely at the connection level: host, port, protocol, and optional auth. It does not manage proxy rotation, health-checking, or session stickiness itself; those behaviors have to come from whatever sits behind the host:port a profile or set_proxy call points at, whether that's a script rotating URLs or a provider's gateway rotating sessions internally. Splash also applies a proxy per render call or per resource, not per browser-context in the way a full browser-automation framework might scope a proxy to a persistent session across multiple page loads. Once a scraping project outgrows a single static gateway and needs routing rules across multiple pools, see how to crawl with Proxy Manager for that next layer.
Conclusion
Splash gives a scraper three levers for routing proxy traffic — a one-off proxy URL parameter, a reusable profile .ini loaded via --proxy-profiles-path, and a Lua request:set_proxy call for per-resource control inside splash:on_request — and all three accept the same host/port/credential shape that a rotating proxy provider issues. Getting proxy routing to actually take effect is mostly a matter of avoiding the two silent failure modes: an unnoticed default.ini profile and an allowlist/denylist mismatch that lets requests through unproxied without raising an error.
FAQ
Q: What proxy protocols does Splash support?
Splash supports http and socks5 in the proxy request parameter and HTTP/SOCKS5 in both proxy-profile .ini files and the Lua request:set_proxytype field; there is no separate HTTPS proxy type, since HTTP-type proxying already handles HTTPS targets through the CONNECT method.
Q: Do I need --proxy-profiles-path to use a proxy at all?
No — --proxy-profiles-path is only required for named, reusable proxy profiles; a one-off proxy can be passed directly as a URL in the proxy request parameter without any special startup flag.
Q: Why does my Splash proxy seem to be ignored on some requests?
The most common causes are a mismatched allowlist/denylist pattern in a proxy profile's [rules] section, a default.ini silently overriding an assumed "no proxy" request, or a request:set_proxy call placed somewhere other than inside splash:on_request before the request is sent.
Q: Can I use a different proxy for different resources on the same page?
Yes — the Lua splash:on_request callback fires once per resource (document, image, script, and so on), so calling request:set_proxy with different values inside that callback routes different resource types through different proxies within a single render call.
Q: Does scrapy-splash need special settings to pass a proxy through?
No extra settings beyond the standard scrapy-splash middleware setup are needed — a proxy key inside a SplashRequest's args dictionary is forwarded to Splash exactly like the proxy query-string parameter on a direct HTTP call.
Q: Does Splash rotate proxy IPs automatically?
No — Splash only routes a request through whatever host, port, and credentials it's given; rotating the actual exit IP over time has to come from the proxy provider's gateway (for example, a rotating-session mode) or from a script that changes the proxy value between requests.
Q: Is this workflow limited to authorized scraping targets?
Yes — everything in this article assumes access to publicly available pages under a site's terms; routing traffic through a proxy does not authorize bypassing authentication, paywalls, or access controls on non-public data.
Ivy Lin
Aug. 19th 2026
110M+ real IPs with 99.9% access success
Blazing-fast average response ~0.5s for high-concurrency tasks
From only $0.1/GB
Get immediate access to premium residential, datacenter, IPv6 and ISP proxy pools.