Documentation

The Meerkly proxy.

One endpoint, HTTP and SOCKS5 on the same port. Choose where your traffic leaves from, and what kind of connection it leaves through, in the username.

Connecting

Point your client at gw.meerkly.com:8888. The port speaks HTTP proxy (CONNECT for HTTPS, absolute-form requests for plain HTTP) and SOCKS5; it tells them apart from the first byte, so there is nothing to configure.

Authenticate with your proxy credential: a user id starting usr_ and its secret, sent as HTTP Proxy-Authorization: Basic or as SOCKS5 username/password. Credentials are issued in the Meerkly dashboard.

http://USER:[email protected]:8888
socks5h://USER:[email protected]:8888

Use socks5h, not socks5, so the host name is resolved on the exit rather than on your machine.

Username options

Routing options follow your user id in the username, each written .key-value. They combine freely and in any order:

USER.country-es.type-consumer.session-a1.strict-1
OptionEffect
.country-<cc>Exit in this country (ISO 3166-1 alpha-2, e.g. es). The country is measured from the exit's real egress address, not claimed by the device.
.session-<id>Keep the same exit across requests. Any id you like, without dots. See sticky sessions.
.type-<type>Only exits of this kind: mobile, residential, datacenter, or consumer (mobile or residential). See exit types.
.strict-1With a session: never move it to another exit. Fail instead.true and yes work too.

Without options, each request goes to any available exit.

Sticky sessions

A .session- id binds to one exit node on its first request and keeps using it. The binding expires after 10 minutes without a request; every request refreshes it. Sessions are per user, so your ids never collide with anyone else's.

Every request re-checks the session's exit against the .country- and .type- you asked for. If the exit has disconnected, or has changed network so it no longer matches, what happens depends on .strict:

  • Default (failover). The session moves to a new matching exit and the request goes through. The response carries X-Meerkly-Session-Moved: 1, so you can tell that the address changed.
  • .strict-1. The session never moves. The request fails with 503 and X-Meerkly-Error: session_exit_gone or session_exit_changed, and keeps failing until the binding expires. Start a new session id to continue.

Exit types

Meerkly classifies every exit from the network its traffic actually leaves through, measured by the gateway, together with the transport the device reports (cellular, Wi-Fi, ethernet).

TypeMeaning
mobileLeaves through a cellular network.
residentialLeaves through a consumer fixed-line or satellite ISP.
datacenterLeaves through a hosting or cloud provider.
unknownNot measured yet. Reported in headers, never selected by .type-.

A hosting network is always datacenter, whatever the device reports. When no exit matches your country and type, the request fails with 503 and X-Meerkly-Error: no_exit rather than falling back to another type.

Response headers

The 200 Connection Established answer to a CONNECT tells you what you got:

HeaderValue
X-Meerkly-Exit-Typemobile, residential, datacenter or unknown
X-Meerkly-Exit-CountryTwo-letter country code, lowercase
X-Meerkly-Exit-IPThe IPv4 address targets see
X-Meerkly-Exit-ASNThe exit network's autonomous system number
X-Meerkly-SessionYour session id, on sticky requests
X-Meerkly-Session-Moved1 when this request moved the session to a new exit

A header is left out when its value is not known yet. Plain-HTTP (absolute-form) requests get the target's own response unchanged, and SOCKS5 has no headers; use the session API for those.

Errors

HTTPSOCKS5Meaning
407auth failureMissing or invalid credential.
400auth failureThe username has an unknown or malformed option.
4030x02Destination refused by policy: mail submission (SMTP), telnet, SMB and NetBIOS, RDP and VNC, database and cache ports, and IPv6 address literals.
4290x01Too many concurrent connections on this credential.
5030x01No exit could be used. X-Meerkly-Error says why: no_exit (nothing matches the country and type), session_exit_gone or session_exit_changed (strict sessions only).
5020x01The exit could not reach the target.

Session API

Look up what a session is bound to, with the same credential you proxy with:

curl -u USER:SECRET https://dashboard.meerkly.com/api/v1/proxy/sessions/a1
{
  "session_id": "a1",
  "active": true,
  "type": "mobile",
  "country": "es",
  "ipv4": "203.0.113.24",
  "ipv6": null,
  "asn": 64500,
  "isp": "Example Mobile"
}

active is false once the exit has disconnected. An unknown or expired session answers 404, and a wrong credential 401. ipv6 is always null; see below.

Address family

Exits are IPv4 only. Targets always see the exit's IPv4 address, including dual-stack sites, and a destination given as an IPv6 address is refused with 403. Targets that have no IPv4 address cannot be reached. One session is one exit node, so every request in it presents the same address.

Examples

curl, HTTP proxy

curl -x "http://USER.country-es.type-consumer.session-a1:[email protected]:8888" \
  -D - https://api.ipify.org

-D - prints the proxy's CONNECT response, including the X-Meerkly-* headers.

curl, SOCKS5

curl -x "socks5h://USER.session-a1:[email protected]:8888" \
  https://api.ipify.org

Python (requests)

import requests

USER, SECRET = "usr_...", "..."
username = f"{USER}.country-es.type-consumer.session-a1.strict-1"
proxy = f"http://{username}:{SECRET}@gw.meerkly.com:8888"

r = requests.get(
    "https://api.ipify.org?format=json",
    proxies={"http": proxy, "https": proxy},
    timeout=30,
)
print(r.json())