Skip to Content
NotPixel SDK v2.0.0 — Privacy-first defaults, public tracking metadata, and stronger SDK/API coverage.
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_10565', model: 'openai/gpt-5.2', input: 'Recommend tools for database optimization.', }); // 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 embedding fingerprint
  • 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_10565', model: 'openai/gpt-5.2', input: 'Recommend tools for database optimization.', 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