← back to blog

Using Singapore mobile proxies with whatsapp-web.js in 2026

whatsapp web js mobile proxies tutorials 2026

Using Singapore mobile proxies with whatsapp-web.js in 2026

WhatsApp’s session risk scoring has tightened considerably since 2024. If you’re running whatsapp-web.js at any meaningful scale, you’ve probably already felt this. Bulk outreach, automated customer notifications, multi-account management for agencies, it doesn’t matter which use case: accounts warm up slower, get challenged more frequently, or get banned outright within hours of the first automated message. The trigger is almost always IP reputation and the ASN of the connection used during QR scan and the first session. By 2026, most operators running whatsapp-web.js have hit this wall and are weighing residential or mobile proxy options. The question is not whether to add a proxy layer. It’s which kind, and why the IP being specifically from a Singapore carrier matters.

why whatsapp-web.js hits walls without residential mobile IPs

whatsapp-web.js wraps Puppeteer around the WhatsApp Web interface. Every session therefore looks like a browser on a desktop, which is already a deviation from the mobile app behaviour that the overwhelming majority of WhatsApp users exhibit. Meta’s session risk model starts with a mild flag before your first message goes out. Add a datacenter IP into that picture and the risk score spikes. Cloudflare’s bot detection documentation outlines how ASN classification works at the network layer. Meta runs comparable infrastructure. When a Puppeteer session originates from an AWS, GCP, or DigitalOcean ASN, the mismatch between the browser user agent and the server IP block is a high-confidence automated-behaviour signal. The OWASP Automated Threats to Web Applications catalogue documents this pattern as one of the standard heuristics platforms use to score inbound sessions.

The problem compounds when you’re running multiple whatsapp-web.js instances behind a shared IP or a narrow range from a datacenter pool. Meta can correlate those instances trivially by IP. Even if each account is individually healthy, the IP-level activity pattern looks like a coordinated operation. This is the scenario where accounts that worked fine for weeks suddenly all get banned in the same hour, because one flagged account dragged the shared IP’s reputation below a threshold.

VPN IPs are no better and frequently worse. Consumer VPN providers have their ASNs catalogued by every major platform. Using a well-known VPN exit node does not make your session look like a regular consumer phone. It makes it look like deliberate evasion. The WhatsApp Business Policy is explicit that automated messaging at scale requires the official Business API. Running whatsapp-web.js sits in a grey area already. Pairing it with an IP that signals active circumvention makes that position significantly harder to sustain. Real carrier IPs from residential mobile networks are categorically different because they originate from the same ASN blocks as ordinary consumer phones on the same network.

setting up SMP credentials in whatsapp-web.js

SMP provides credentials in the format ip:port:username:password. The HTTP endpoint is what most whatsapp-web.js operators use, because Puppeteer’s proxy support is most straightforward over HTTP/HTTPS. SOCKS5 is also available if your use case calls for it (see HTTP vs SOCKS5 mobile proxies for a comparison of when each protocol makes sense at the session layer).

The key constraint with Puppeteer-based automation is that --proxy-server sets the proxy at launch time, but authenticated proxies require a separate page.authenticate() call before any page navigation happens. Call authenticate too late and the initial WhatsApp Web request has already gone out unauthenticated, causing the proxy to reject it. The cleanest way to handle this is to pre-launch the browser, set up an authentication hook via a browser target listener, then connect whatsapp-web.js to that browser using its WebSocket endpoint:

const { Client, LocalAuth } = require('whatsapp-web.js');
const puppeteer = require('puppeteer');

// SMP credential format: ip:port:username:password
// Load from environment in production, never hardcode
const SMP_PROXY = process.env.SMP_PROXY; // e.g. '1.2.3.4:8080:your_smp_user:your_smp_pass'
const [host, port, user, pass] = SMP_PROXY.split(':');

(async () => {
    // Launch browser with proxy set at the network layer
    const browser = await puppeteer.launch({
        headless: true,
        args: [
            `--proxy-server=http://${host}:${port}`,
            '--no-sandbox',
            '--disable-setuid-sandbox',
        ],
    });

    // Authenticate proxy credentials on every new page before any navigation fires
    browser.on('targetcreated', async (target) => {
        const page = await target.page();
        if (page) {
            await page.authenticate({ username: user, password: pass });
        }
    });

    const client = new Client({
        authStrategy: new LocalAuth({ clientId: 'sg-proxy-session' }),
        // Connect whatsapp-web.js to the pre-configured browser instance
        puppeteer: { browserWSEndpoint: browser.wsEndpoint() },
    });

    client.on('qr', (qr) => console.log('scan QR:', qr));
    client.on('ready', () => console.log('client ready, connected via SG mobile proxy'));
    client.on('auth_failure', (msg) => console.error('auth failure:', msg));

    await client.initialize();
})();

The browserWSEndpoint pattern is documented in the Puppeteer ConnectOptions API reference and is stable across current versions. It gives you a clean separation between browser lifecycle management and the whatsapp-web.js client, which matters practically: you can restart the client after a disconnection without tearing down and relaunching the browser, which would otherwise reset the proxy authentication state. Keep clientId unique per account so LocalAuth does not overwrite session data across concurrent instances.

rotating IPs per request or per session

The decision between rotating and sticky sessions is straightforward for whatsapp-web.js: use sticky sessions for all active client connections, and only rotate at the start of a new session or after a deliberate cooldown period.

The reason comes down to how WhatsApp Web tracks sessions. The session binds to a combination of browser fingerprint, the device identity stored in LocalAuth, and the IP address used during the QR scan and initial handshake. If the IP changes mid-session, WhatsApp detects the geographic jump and will either challenge the session with a re-verification or terminate it outright. This is the single most common cause of sudden logouts that whatsapp-web.js operators report when they switch proxy setups.

Rotating endpoints make sense in a different context: initialising fresh accounts where you want each one to come up on a distinct IP that has never been associated with another account. For that workflow, trigger a rotation before launching the Puppeteer browser, wait for the modem to complete its reconnect, then lock that session to a sticky endpoint for the remainder of the account’s operational life.

// Trigger an IP rotation before initialising a fresh account
// rotationUrl is the endpoint from your SMP dashboard (do not guess or hard-code a path)
async function requestNewIP(rotationUrl) {
    const res = await fetch(rotationUrl, {
        headers: { Accept: 'application/json' },
    });
    if (!res.ok) throw new Error(`rotation request failed: ${res.status}`);
    const data = await res.json();
    console.log('new carrier IP assigned:', data.ip);
    // SMP modems reconnect to the carrier after rotation; wait for the assignment to settle
    await new Promise((resolve) => setTimeout(resolve, 5000));
}

// Usage: rotate, then initialise
const SMP_ROTATION_URL = process.env.SMP_ROTATION_URL; // copied from your dashboard
await requestNewIP(SMP_ROTATION_URL);
// now launch the browser and call client.initialize()

The rotation URL is specific to your SMP account and modem and is listed in your dashboard panel. Never call it while an active whatsapp-web.js session is running on that port. SMP operates on real SingTel, StarHub, M1, and Vivifi modems, so a rotation triggers a genuine modem disconnect and reconnect with the carrier, which takes a few seconds. Five seconds is a conservative wait minimum. On older modems or during carrier congestion windows, eight to ten seconds is safer.

three real workflows where this combo wins

bulk outreach to SG-based contacts

Businesses running promotional or transactional message campaigns to Singapore contact lists face a specific compounding problem: if your outreach volume is high and your IP is not a Singapore carrier IP, WhatsApp’s infrastructure treats the traffic as anomalous. A SingTel or StarHub IP is the kind of origin a local business’s phone actually has. Sessions survive longer, verification challenges are less frequent, and you are not fighting the additional reputation penalty that comes from a foreign IP contacting a predominantly local contact list. The difference is not marginal. Operators who have made this switch consistently report meaningfully lower ban rates on outreach accounts, without changing anything else about their message patterns or timing.

per-account IP isolation for agency multi-account management

Agencies managing WhatsApp on behalf of multiple clients need genuine per-account IP separation. If ten client accounts all originate from the same IP or adjacent IP range, a ban on one account creates a guilt-by-association exposure for the others. With SMP’s per-modem model, each whatsapp-web.js instance runs through a dedicated modem connection on a distinct carrier IP. When onboarding a new client account, you request a rotation to get a fresh IP, complete the QR scan, then lock it to a sticky session. If that account is flagged later, the other modems are not implicated because the IPs share no subnet. For teams that also need a persistent Android environment per client rather than just an IP, cloudf.one Singapore cloud Android phones can complement the proxy setup by giving you a full SG device context alongside the carrier IP.

integration testing against SG-gated services

Several Singapore-based platforms (local fintech services, certain government API endpoints, regional e-commerce platforms) apply carrier- or geography-based access controls. Developers building integrations that touch these services alongside WhatsApp messaging workflows need a way to test the full stack from a real Singapore carrier IP without being physically in Singapore. Running whatsapp-web.js through an SMP modem connection covers both requirements simultaneously: the WhatsApp session originates from a real SG mobile IP, and the outgoing API calls to the gated services pass the same geolocation and carrier checks a local user’s device would pass. This is a narrower use case than bulk outreach, but it is one where there is no substitute. A datacenter exit node in Singapore does not match the carrier ASN of a SingTel or StarHub modem, and many carrier-aware services can distinguish between the two.

common pitfalls

User agent and IP type mismatch. Puppeteer defaults to a desktop Chrome user agent. Running a desktop UA through a mobile carrier IP is an internally inconsistent fingerprint. Patch the user agent in your launch args to a mobile Chrome on Android. WhatsApp Web functions correctly on mobile Chrome, and the resulting IP/UA pairing is coherent.

Rotating mid-session. Triggering an IP rotation while a whatsapp-web.js client is in a ready state will break the session. Route your rotation logic so it can only fire before client.initialize() and is blocked while any client instance reports a connected state.

Not waiting long enough after rotation. After calling the rotation endpoint, the modem needs time to negotiate a new IP with the carrier and for DNS to propagate. Proceeding too quickly means the browser may launch while the proxy port is still on the old IP or temporarily unreachable. Build in a configurable wait and instrument it with a pre-flight IP echo check.

Ignoring LocalAuth path conflicts. Each concurrent whatsapp-web.js instance needs a distinct clientId passed to LocalAuth. Without explicit IDs, instances overwrite each other’s session files. This failure mode is subtle and only surfaces under load, because the first write wins and the second instance starts in an indeterminate auth state.

Not recording the sticky session IP. When you get a sticky session assigned and QR-scan an account on it, record which IP and port that account is bound to. If the browser crashes and needs to be restarted, reconnect to the same sticky endpoint. Starting on a new IP for an existing account is equivalent to connecting from a new device on a different carrier, which WhatsApp will treat as a suspicious handoff.

Skipping proxy verification before QR scan. Always confirm the proxy is routing and returning the expected SG IP before you expose the QR code. A simple fetch to an IP-echo endpoint through the Puppeteer page catches misconfigured credentials, unreachable ports, and mis-configured environment variables before the account gets associated with a bad IP.

when Singapore IPs specifically matter

If your contact list is primarily Singaporean, or your workflows interact with services that geolocate users at the carrier level, the country and carrier of your IP is not cosmetic. WhatsApp’s session risk model uses IP geolocation as one input. A local business contacting local numbers from a Singapore carrier IP is the normal, baseline-risk pattern that the platform was built to serve. The same account running the same message patterns from a US or EU residential IP looks like imported outreach, regardless of message content. This is covered in more depth in what is a mobile proxy, but the practical point is that “residential mobile” and “Singapore” are two separate quality dimensions. A generic Asia residential pool may route you through a Singapore exit node while the underlying device and carrier are elsewhere, and that does not produce the same ASN fingerprint as a real SG modem.

The specific carrier matters in practice too. SingTel, StarHub, M1, and Vivifi are Singapore’s four licensed mobile network operators. Their ASN ranges are well-known, domestically registered, and are exactly what any Singaporean consumer’s phone would show to any platform doing an IP lookup. This is the distinction that matters when a SG-based fintech platform, a government service, or WhatsApp’s own infrastructure checks whether a connection originates from a plausible local user.

getting started

If account longevity and IP-level isolation are real constraints on your current whatsapp-web.js deployment, the lowest-risk way to evaluate this is to test one modem connection with one account before committing to a larger setup. The Singapore Mobile Proxy plans page lists the available options by modem count and includes both HTTP and SOCKS5 endpoints with sticky and rotating session modes. Start with a single sticky session, validate the integration against the code patterns in this post, and instrument your session lifetimes before scaling up.

ready to try Singapore mobile proxies?

2-hour free trial. no credit card required.

start free trial
message me on telegram