Skip to Content
NotPixel SDK v1.0.1 — Now with caching, hooks, and browser tracking!
FeaturesRequest Deduplication

Request Deduplication

Automatic deduplication of parallel requests for the same input. This prevents redundant API calls when multiple parts of your application request the same ad simultaneously.

How It Works

When multiple getAd() calls are made for the same input before the first one completes, they all share the same API request:

const ads = new Ads({ publisherId: 'pub-xxx' }); // Fire 3 parallel requests for the same input const [ad1, ad2, ad3] = await Promise.all([ ads.getAd({ input: 'database optimization' }), ads.getAd({ input: 'database optimization' }), ads.getAd({ input: 'database optimization' }), ]); // Only 1 API call was made! // All 3 return the same ad console.log(ad1?.id === ad2?.id); // true console.log(ad2?.id === ad3?.id); // true

Deduplication is automatic and requires no configuration. It works with or without caching enabled.

Benefits

BenefitDescription
Reduced API callsParallel requests share a single network call
Lower latencySubsequent requests get the result immediately
Cost savingsFewer requests = lower API costs
Rate limit protectionHelps avoid hitting rate limits

Different Inputs

Requests with different inputs are not deduplicated:

// These make 3 separate API calls const [ad1, ad2, ad3] = await Promise.all([ ads.getAd({ input: 'query 1' }), ads.getAd({ input: 'query 2' }), ads.getAd({ input: 'query 3' }), ]); // Each gets a different ad console.log(ad1?.id !== ad2?.id); // true

Deduplication Key

Requests are deduplicated based on:

  • Publisher ID
  • Input text (or text hash in signals mode)
  • Privacy mode
// These are deduplicated (same key) ads.getAd({ input: 'query' }); ads.getAd({ input: 'query' }); // These are NOT deduplicated (different inputs) ads.getAd({ input: 'query 1' }); ads.getAd({ input: 'query 2' }); // These are NOT deduplicated (different publishers) ads.getAd({ input: 'query', publisherId: 'pub-a' }); ads.getAd({ input: 'query', publisherId: 'pub-b' });

With Caching

Deduplication works alongside caching:

  1. Cache miss + first request: Creates in-flight request
  2. Cache miss + parallel request: Shares in-flight request
  3. Cache hit: Returns immediately from cache (no in-flight request needed)
const ads = new Ads({ publisherId: 'pub-xxx', cache: true }); // First batch: 1 API call (deduplication) await Promise.all([ ads.getAd({ input: 'query' }), ads.getAd({ input: 'query' }), ]); // Second batch: 0 API calls (cache hit) await Promise.all([ ads.getAd({ input: 'query' }), ads.getAd({ input: 'query' }), ]);

Error Handling

If a deduplicated request fails, all waiting requests receive the same error:

const results = await Promise.allSettled([ ads.getAd({ input: 'query' }), ads.getAd({ input: 'query' }), ads.getAd({ input: 'query' }), ]); // If the single API call fails, all 3 are rejected results.forEach(r => { if (r.status === 'rejected') { console.log('All failed with:', r.reason); } });

Cleanup

In-flight requests are automatically cleaned up:

  • On success: Removed after result is returned
  • On error: Removed after error is thrown

This ensures subsequent requests make fresh API calls.

Batch Requests

adsBatch() also benefits from deduplication:

// If inputs have duplicates, only unique inputs are fetched await ads.adsBatch({ inputs: ['q1', 'q1', 'q2', 'q2', 'q3'], }); // Makes 3 API calls, not 5

Implementation Note

Deduplication uses an in-memory Map of Promises. When a request starts:

  1. Check if there’s an in-flight request for this key
  2. If yes, return the existing Promise
  3. If no, create the request and store the Promise
  4. When complete, remove from the map