How Worldmonitor Fetches Polymarket Prediction Market Contracts with JA3 Fingerprint Bypass
Worldmonitor retrieves Polymarket contracts through a Redis-backed bootstrap cache first, then falls back to a direct Gamma API call using a Chrome User-Agent, gracefully tolerating Cloudflare JA3 fingerprint blocks by returning empty market lists rather than throwing errors.
The koala73/worldmonitor repository implements a resilient fetching strategy for Polymarket prediction market contracts that anticipates and handles TLS fingerprint-based blocking. By combining server-side caching with browser-mimicking HTTP headers, the system ensures continuous data availability even when Cloudflare's JA3 detection rejects automated server connections.
Understanding the JA3 Fingerprint Challenge
Cloudflare and similar edge security providers use JA3 fingerprinting to identify TLS handshake characteristics unique to specific clients. Server-side code libraries (like Node.js fetch or https modules) generate TLS signatures that differ from genuine Chrome or Firefox browsers, making them trivial to block. The Gamma API (gamma-api.polymarket.com) sits behind such protection, which means direct server-to-server requests often receive HTTP 403 or connection resets regardless of valid headers.
Rather than attempting complex TLS spoofing or proxy rotation, Worldmonitor acknowledges this constraint explicitly in the source code—it does not truly bypass the JA3 check—and instead architected a defensive fetching pattern that prioritizes cached data and degrades gracefully when the live API is unreachable.
The Two-Stage Fetch Architecture
The RPC handler in server/worldmonitor/prediction/v1/list-prediction-markets.ts implements a priority-based data retrieval flow that minimizes network exposure to the protected endpoint.
Stage 1: Redis Bootstrap Cache
Before attempting any external network call, the handler checks a Redis-backed bootstrap cache keyed by BOOTSTRAP_KEY. This cache contains pre-hydrated market data ingested through alternative means, providing a zero-cost, zero-risk lookup path.
// From server/worldmonitor/prediction/v1/list-prediction-markets.ts
const cached = await redis.get(BOOTSTRAP_KEY);
if (cached && !request.query) {
return parseBootstrap(cached);
}
If the cache hits and no specific query filters are applied, the function returns immediately, completely avoiding the JA3-protected Gamma API.
Stage 2: Gamma API Fallback with Browser Headers
When the bootstrap cache misses or the request includes specific search criteria, the handler constructs a URL for https://gamma-api.polymarket.com and issues a fetch using a Chrome-style User-Agent defined in server/_shared/constants.ts as CHROME_UA. The request includes an 8-second timeout to prevent hanging on blocked connections.
const response = await fetch(
`${GAMMA_BASE}/${endpoint}?${params}`,
{
headers: {
Accept: 'application/json',
'User-Agent': CHROME_UA
},
signal: AbortSignal.timeout(FETCH_TIMEOUT),
},
);
if (!response.ok) return null; // Cloudflare JA3 block returns non-OK
The code comments explicitly note that this fetch may fail due to Cloudflare's JA3 detection. Instead of retrying or crashing, the handler treats a non-OK response as an expected condition and returns null, which propagates as an empty market list to the client.
Client-Side Resilience and Circuit Breaking
The front-end client located in src/services/prediction/index.ts wraps the gRPC-like PredictionServiceClient with additional resilience layers. A circuit breaker caches successful listPredictionMarkets RPC responses for 10 minutes, preventing repeated hammering of the server-side handler when the Gamma API is being actively blocked.
import { fetchPredictions } from '@/services/prediction';
// Returns up to 15 markets; falls back to empty array if JA3 block active
const markets = await fetchPredictions();
console.log('Polymarket contracts:', markets);
The fetchPredictions helper invokes client.listPredictionMarkets(...) and handles the empty-list scenario gracefully, ensuring the UI renders "no markets available" rather than a fatal error state.
Implementation Reference
For direct serverless or backend integration, you can invoke the RPC client manually:
import { PredictionServiceClient } from '@/generated/client/worldmonitor/prediction/v1/service_client';
const client = new PredictionServiceClient('', {
fetch: (...args) => globalThis.fetch(...args),
});
const response = await client.listPredictionMarkets({
category: 'politics',
query: '',
pageSize: 50,
cursor: '',
});
console.log(response.markets); // Empty array if Cloudflare blocks the server
Key files involved in this architecture:
server/worldmonitor/prediction/v1/list-prediction-markets.ts– RPC implementation containing the bootstrap cache logic and JA3-aware Gamma API fetch.src/services/prediction/index.ts– Front-end wrapper with circuit breaker and 10-minute result caching.server/_shared/constants.ts– DefinesCHROME_UA, the browser User-Agent string used to mimic legitimate Chrome traffic.
Summary
- Worldmonitor does not spoof JA3 fingerprints; it accepts that server-side TLS signatures may be blocked by Cloudflare and architects around the limitation.
- A Redis bootstrap cache (
BOOTSTRAP_KEY) provides primary data sourcing, eliminating network requests entirely when pre-hydrated data is available. - Fallback fetches to
gamma-api.polymarket.comuse a Chrome User-Agent (CHROME_UA) and 8-second timeouts, but explicitly expect and handle HTTP failures caused by JA3 blocking. - Graceful degradation ensures that when the Gamma API is unreachable, the system returns empty lists rather than errors, maintaining application stability.
- Client-side circuit breaker caching prevents repeated attempts to the blocked endpoint during active Cloudflare challenges.
Frequently Asked Questions
Does Worldmonitor actually bypass the JA3 fingerprint check?
No. According to the source code comments in server/worldmonitor/prediction/v1/list-prediction-markets.ts, the repository does not implement TLS fingerprint spoofing or JA3 evasion techniques. Instead, it attempts a standard HTTPS request with browser-like headers and accepts that Cloudflare may reject the connection based on the server's TLS signature. When blocked, it returns cached or empty data rather than attempting to "bypass" the security control.
What is the primary data source when the Gamma API is blocked?
The Redis bootstrap cache serves as the authoritative source when live API calls fail. The handler checks for a pre-existing BOOTSTRAP_KEY entry before ever reaching out to Polymarket's servers. If this cache is populated—typically through a separate ingestion process or manual seeding—the end user receives fresh market data even while the JA3-protected direct fetch returns nothing.
How long are successful API responses cached on the client side?
Successful responses are cached for 10 minutes via the circuit breaker pattern implemented in src/services/prediction/index.ts. This prevents the front-end from repeatedly invoking the server RPC—and by extension, the Gamma API—when the system is already known to be in a healthy state, reducing load and latency.
Why use a Chrome User-Agent if JA3 fingerprinting happens at the TLS layer?
While JA3 fingerprinting operates on the TLS handshake characteristics (cipher suites, extensions, elliptic curves), Worldmonitor still sends a Chrome User-Agent (CHROME_UA) to maintain HTTP-level consistency. This ensures that if the request does pass the TLS inspection—either due to Cloudflare configuration changes or future proxy implementations—the subsequent HTTP evaluation sees consistent browser headers, reducing the risk of secondary blocking based on header anomalies.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →