Using Singapore mobile proxies with Selenium in 2026
Using Singapore mobile proxies with Selenium in 2026
At some point in almost every Selenium project targeting Southeast Asian platforms, the same pattern shows up. The script works cleanly in local dev, passes CI, then starts hemorrhaging 403s and CAPTCHA challenges the moment traffic volume picks up or the target site tightens its bot detection. The instinct is usually to rotate IPs faster or spoof headers more aggressively. Those fixes treat the symptom. The underlying problem is that the IP block being used looks nothing like what a real Singapore user on a real Singapore carrier looks like, and that gap is what mobile proxies close.
why Selenium hits walls without residential mobile IPs
Selenium drives a real browser, so it clears a lot of fingerprinting checks that headless curl requests fail. TLS handshake, JavaScript execution, canvas rendering, font enumeration, WebGL signatures: all of these look legitimate with Selenium. What it cannot fake is the IP reputation layer. Datacenter IPs, even well-maintained ones, carry ASN signatures that identify them as hosting providers within milliseconds of a TCP connection. Sites running commercial bot detection (Cloudflare, Akamai, DataDome, PerimeterX) score IPs before a single HTTP request byte is processed. A Selenium session coming from a DigitalOcean or AWS IP is already behind on points before the browser fingerprint is even evaluated.
VPNs are marginally better but share the same core problem. Most commercial VPN exit nodes are well-catalogued by threat intelligence feeds, and their ASNs cluster into a small set of providers that are trivially blocklisted. Residential proxies from large EU or US pools are a step up. But for sites that serve Singapore-specific content or enforce geo-restrictions at the carrier level, a US residential IP produces either incorrect localized content or an outright redirect. Testing Grab, Shopee, Lazada Singapore, Singpass, or any SG banking app with a non-SG IP gives you a completely different response surface than what an actual Singapore user sees.
Mobile IPs on real carrier networks (SingTel, StarHub, M1, Vivifi) sit in the CGNAT space that carriers use for their subscriber base. These IP ranges are assigned to real handsets on real mobile plans. They get rotated by the carrier, carry legitimate ASN metadata, and appear in exactly the right geolocation databases. Bot detection systems tuned to flag datacenter and proxy ASNs have no reliable signal against genuine carrier IPs, because those same ranges are used by millions of real users every day. That is the actual value proposition, not a marketing claim about “residential” quality.
setting up SMP credentials in Selenium
SMP credentials follow the format ip:port:username:password. The proxy host and port identify the endpoint; authentication is handled per-request using the username and password pair. Selenium WebDriver does not support authenticated proxies natively through its proxy settings API (the Proxy object has no auth field), so you need to handle authentication through one of two approaches: an extension that injects the credentials, or a local proxy tunnel (like mitmproxy or Squid) that forwards authenticated requests.
The extension approach is the most portable for Chrome and Chromium-based drivers. Here is a working implementation using Python, selenium, and the selenium-wire library, which intercepts requests at the driver level and lets you pass proxy authentication cleanly:
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
PROXY_HOST = "sg1.singaporemobileproxy.com"
PROXY_PORT = 10000
PROXY_USER = "your_username"
PROXY_PASS = "your_password"
proxy_options = {
"proxy": {
"http": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
"https": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
"no_proxy": "localhost,127.0.0.1",
}
}
chrome_options = Options()
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(
seleniumwire_options=proxy_options,
options=chrome_options,
)
driver.get("https://www.grab.com/sg/")
print(driver.title)
driver.quit()
The --disable-blink-features=AutomationControlled flag matters here. Without it, navigator.webdriver returns true, which is a common first-pass fingerprint check. Passing that flag and pairing it with a genuine SG mobile IP puts you in a significantly better position against detection systems that cross-reference IP reputation with browser signals.
If you are running Firefox via geckodriver, selenium-wire works the same way. For headless Chrome in a CI environment, add --headless=new (not the legacy --headless flag, which has a different rendering fingerprint) and make sure your user-agent string matches what a real Chrome on Android would report for your target market, not the default headless Chrome UA.
rotating IPs per request or per session
The choice between rotating and sticky sessions is a workflow decision, not a preference. If your Selenium script performs a single discrete action per session (a price check, a search result capture, a single product page load) and does not need to maintain login state or a shopping cart across requests, rotating mode gives you maximum IP diversity. Each new WebDriver instance or each call to a rotation endpoint draws a different carrier IP from the pool.
Sticky sessions are necessary any time you need continuity across multiple requests in the same logical user journey. Logging into a platform, navigating through paginated results while authenticated, adding items to a cart, completing a checkout flow: all of these require the same IP for the duration of the session. The server ties session tokens to the originating IP. Change the IP mid-session and the application will typically invalidate the cookie and force a re-login, which breaks your script and trips account-security alerts.
SMP provides separate endpoints for rotating and sticky modes. To use sticky sessions, you include a session identifier in the username field, which pins your connection to a specific modem for the duration of that session window:
import uuid
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
def make_driver(sticky=False, session_ttl_minutes=10):
proxy_user = "your_username"
proxy_pass = "your_password"
if sticky:
session_id = uuid.uuid4().hex[:8]
proxy_user = f"your_username-session-{session_id}-ttl-{session_ttl_minutes}"
proxy_options = {
"proxy": {
"http": f"http://{proxy_user}:{proxy_pass}@sg1.singaporemobileproxy.com:10000",
"https": f"http://{proxy_user}:{proxy_pass}@sg1.singaporemobileproxy.com:10000",
}
}
options = Options()
options.add_argument("--disable-blink-features=AutomationControlled")
return webdriver.Chrome(seleniumwire_options=proxy_options, options=options)
# rotating: new driver per task
driver = make_driver(sticky=False)
driver.get("https://shopee.sg/")
driver.quit()
# sticky: same IP for a logged-in session
driver = make_driver(sticky=True, session_ttl_minutes=15)
driver.get("https://shopee.sg/buyer/login")
# ... complete login flow ...
driver.quit()
Check the SMP documentation for the exact session parameter syntax, as the username modifier format is defined there and may be updated. Do not hardcode a session token across different script runs unless you explicitly want to reuse a specific modem IP.
three real workflows where this combo wins
verifying geo-fenced content on Singapore platforms
Many SG platforms serve different price tiers, promotional banners, and product availability depending on whether the visitor is detected as a Singapore mobile user versus a foreign user or a datacenter IP. A Selenium script verifying that your production site displays the correct SGD pricing, the right promotional copy, and the correct carrier-billing options to Singapore users cannot do that job reliably from a non-SG or non-mobile IP. With SMP, you are making HTTP requests through an actual SingTel or StarHub handset. The IP geolocation lookup, the carrier detection, and the ASN classification all resolve correctly. The content your scraper sees matches what your actual customers see.
automated QA for banking and fintech apps
SG banking and fintech apps (DBS, OCBC, GXS, and similar) implement IP-based risk scoring as part of their login and transaction flows. Datacenter IPs frequently trigger step-up authentication challenges or outright session blocks, making automated UI testing against these environments impractical. Mobile proxies on real SG carrier IPs sit inside the same IP risk tier as ordinary retail customers, which lets QA automation scripts exercise login flows, OTP screens, and transaction confirmation pages without being diverted into elevated-risk authentication paths. See ethical mobile proxy use for the relevant considerations when running automated tests against financial services environments.
competitive price monitoring across SEA marketplaces
Selenium-based price monitors that scrape Shopee SG, Lazada SG, Carousell, and similar platforms run into two distinct problems with non-mobile IPs: rate limiting triggered by ASN reputation, and geo-filtered results that show different prices or stock levels to foreign requestors. Running these scripts through SMP’s rotating pool means each request comes from a different real SG mobile subscriber IP. That distributes the rate-limit surface and means the scraped prices reflect what Singapore users actually see, not a foreign-visitor view. For SEO and market research applications, mobile proxies for SEO research covers the broader search-result verification use case.
common pitfalls
-
user-agent mismatch with mobile IPs. an SG carrier IP paired with a default desktop Chrome UA is a mismatched signal. bot detection systems correlate IP type (mobile carrier) with user-agent (desktop browser) and flag the anomaly. use a UA string that matches the device type implied by the IP, or use a desktop UA paired with a sticky session that is consistently associated with one UA.
-
IP rotation mid-session breaking cookies. if you call the rotation endpoint or create a new driver instance while a session is active, the server-side session is invalidated. decide upfront whether a given workflow needs sticky sessions, and do not mix rotation and sticky configurations in the same logical user journey.
-
ignoring HTTPS certificate warnings from selenium-wire. selenium-wire acts as a local MITM to intercept requests, which means it presents its own CA certificate. some sites do certificate pinning. if you see TLS errors that do not appear without the proxy, certificate pinning is likely the cause, and you need a different interception approach.
-
reusing the same session token across many requests. a sticky session that runs for hours accumulates a request history that starts to look like automation. keep session TTLs short and scoped to a single logical user journey.
-
not accounting for CGNAT IP sharing. mobile carrier IPs are shared across multiple real subscribers via CGNAT. this means your IP may also be used by other SMP customers or real carrier subscribers simultaneously. it is not a flaw, it is how mobile networks work, and it actually helps with detection, but it means you cannot treat the IP as exclusively yours.
-
geolocation header overrides conflicting with the proxy IP. some test setups inject
X-Forwarded-Foror similar headers to simulate a location, and then also route through a proxy. these override headers are often stripped or ignored by the target site anyway, but if they conflict with the real IP geolocation, they can produce inconsistent results.
when Singapore IPs specifically matter
The answer is not just “when you’re targeting SG sites.” Several SEA platforms segment their backend logic not just by country-level geolocation but by ASN and carrier identity. That is a more specific problem than most people expect. Singpass explicitly restricts certain API surfaces based on network origin. Grab’s app-side rate limiting has historically been tuned to its expected user base, which is predominantly mobile users on SG, MY, TH, and PH carriers. Testing these systems from EU residential proxies or US datacenter IPs produces a fundamentally different response surface. Not just different content, but different HTTP status codes, different rate limit windows, and different bot-score thresholds.
There is also the question of what “Singapore residential” actually means in practice. Some proxy providers advertise SG residential IPs that are sourced from fixed-line ISP pools, cloud hosting ASNs, or reclassified datacenter ranges. The distinction matters because mobile carrier IPs carry a different trust profile in every commercial threat intelligence database. SMP runs on physical SingTel, StarHub, M1, and Vivifi SIM cards in real modems. That is a verifiable hardware-layer guarantee, not an IP-classification claim. For Selenium workflows where the goal is to replicate the experience of a real Singapore mobile user, that distinction directly affects whether the automation succeeds or fails. HTTP vs SOCKS5 mobile proxies is worth reading if you’re deciding which protocol to use for your specific Selenium setup, since SOCKS5 handles certain traffic patterns differently in browser contexts.
getting started
If you are evaluating whether to add SMP to an existing Selenium project, the lowest-friction test is to pick one script that is currently hitting blocks or producing geo-incorrect results, wire it through a single SMP credential using the selenium-wire approach above, and run it against your target site for a few hundred requests. The difference in block rate is usually apparent within the first test run. Plans and pricing are on the Singapore Mobile Proxy plans page, with options that scale from low-volume QA testing up to high-concurrency scraping workloads. If you are running multiple concurrent Selenium workers, each worker should get its own session identifier to avoid IP collisions between parallel sessions.