@playanext/playa-yield-sdk
v1.3.0
Published
PlayaYield Chrome Extension Ad Monetization SDK for Manifest V3
Maintainers
Readme
@playanext/playa-yield-sdk
Ad Monetization SDK for Chrome Extensions — Manifest V3 Compliant
A lightweight, fully typed SDK that lets Chrome extension developers display ads and earn revenue through the PlayaYield platform. Built for Manifest V3 with zero remote code execution.
Why PlayaYield?
| | | | ------------------- | ------------------------------------------------------------------- | | MV3 Compliant | No remote code execution — all code ships bundled in your extension | | Lightweight | < 35 KB minified, tree-shakeable, zero dependencies | | Secure | All network requests routed through the background service worker | | Type-Safe | Full TypeScript definitions with IDE autocomplete | | Auto-Tracking | Viewport-based impression tracking and click tracking — zero setup | | Refreshable Ads | Built-in auto-rotating ads for long-lived surfaces like side panels | | Debug Mode | Verbose logging you can toggle at build time or runtime |
Table of Contents
- Installation
- Quick Start
- Where Ads Can Appear
- API Reference
- Use Cases
- Test Mode
- Chrome Web Store Compliance
- Tracking & Privacy
- Error Handling
- Build Output
- Live Example
- Support
- License
Installation
npm install @playanext/playa-yield-sdkPackage details:
- Bundle size: < 35 KB minified
- Zero runtime dependencies
- Tree-shakeable ESM and CJS builds
- Full TypeScript definitions included
Quick Start
1. Initialize in Background Service Worker
// background.ts
import { initializePlayaYield } from '@playanext/playa-yield-sdk';
initializePlayaYield({
apiKey: 'your-api-key',
});2. Configure manifest.json
{
"manifest_version": 3,
"name": "Your Extension",
"version": "1.0.0",
"background": {
"service_worker": "background.js"
},
"permissions": ["storage"]
}No extra permissions required. PlayaYield works within your existing extension permissions. Users won't see any new permission prompts when you add monetization.
3. Display Ads
// popup.ts or sidepanel.ts (NOT a content script)
import { createAd } from '@playanext/playa-yield-sdk';
const { element, impressionId } = await createAd({
placement: 'popup',
size: { width: 300, height: 250 },
});
document.getElementById('ad-slot')!.appendChild(element);That's it — impression and click tracking are handled automatically.
Where Ads Can Appear
PlayaYield ads are designed to appear only within your extension's own UI surfaces. This ensures Chrome Web Store compliance and a non-intrusive user experience.
Allowed:
- Extension Popup
- Side Panel
- Options / Settings Page
- Internal Extension Pages (
chrome-extension://)
Not Allowed:
- Content Scripts (injected into websites)
- User-facing web pages
- Injected iframes on external sites
The SDK automatically detects and blocks ad requests from content scripts. Calling
createAd()orcreateManagedRefreshableAd()from a content script will throw an error.
API Reference
initializePlayaYield(config: SDKConfig): void
Initialize the SDK in your background service worker. Call once when your extension starts.
interface SDKConfig {
/** Your PlayaYield API key (required) */
apiKey: string;
/** Custom API endpoint URL — only needed for enterprise deployments */
baseUrl?: string;
/** Enable verbose SDK logging (default: false) */
debug?: boolean;
}Example:
import { initializePlayaYield } from '@playanext/playa-yield-sdk';
initializePlayaYield({
apiKey: 'your-api-key',
debug: false,
});You can also toggle debug logging at runtime without changing code:
localStorage.setItem('playayield:debug', 'true');
createAd(options: AdOptions): Promise<AdResult>
Request and render a one-time ad. Returns a ready-to-append <div> element.
Must be called from an extension page (popup, side panel, or internal page) — blocked in content scripts.
interface AdOptions {
/** Placement identifier — 'popup' | 'sidepanel' | 'internal' */
placement: 'popup' | 'sidepanel' | 'internal';
/** Ad dimensions. Allowed sizes: 300x250, 320x50, 320x100 */
size: { width: number; height: number };
/** Optional targeting categories */
categories?: string[];
}Returns:
interface AdResult {
/** Ready-to-append div element containing the ad */
element: HTMLDivElement;
/** Unique impression ID for tracking */
impressionId: string;
/** Click-through URL */
clickUrl?: string;
}Example:
import { createAd } from '@playanext/playa-yield-sdk';
try {
const { element, impressionId } = await createAd({
placement: 'popup',
size: { width: 300, height: 250 },
categories: ['tech', 'productivity'],
});
document.getElementById('ad-container')!.appendChild(element);
console.log('Ad displayed:', impressionId);
} catch (error) {
console.error('Failed to load ad:', error);
}createManagedRefreshableAd(options: ManagedRefreshableAdOptions): Promise<ManagedRefreshableAdResult>
Create a fully managed, auto-refreshing ad for long-lived surfaces like side panels. The SDK handles appending, refresh intervals, session impression limits, and cleanup.
Refreshable ads significantly increase revenue compared to static placements because they rotate new creatives automatically. Refresh timing and impression caps are controlled dynamically by the backend.
interface ManagedRefreshableAdOptions {
/** Container element or CSS selector where the ad will be appended */
container: HTMLElement | string;
/** Placement identifier */
placement: 'popup' | 'sidepanel' | 'internal';
/** Ad dimensions. Allowed sizes: 300x250, 320x50, 320x100 */
size: { width: number; height: number };
/** Optional targeting categories */
categories?: string[];
}Returns:
interface ManagedRefreshableAdResult {
/** Stop refreshing and clean up resources */
stop: () => void;
/** Check if the ad is still actively refreshing */
isActive: () => boolean;
}Example — CSS selector:
import { createManagedRefreshableAd } from '@playanext/playa-yield-sdk';
const managed = await createManagedRefreshableAd({
container: '#ad-slot',
placement: 'sidepanel',
size: { width: 300, height: 250 },
});
// Optional: stop when user navigates away
window.addEventListener('beforeunload', () => managed.stop());Example — element reference:
const managed = await createManagedRefreshableAd({
container: document.getElementById('ad-slot')!,
placement: 'sidepanel',
size: { width: 300, height: 250 },
});Auto-cleanup: The SDK uses a
MutationObserverto detect when the container is removed from the DOM and stops the refresh cycle automatically.
Use Cases
Banner Ad in Popup
import { createAd } from '@playanext/playa-yield-sdk';
const { element } = await createAd({
placement: 'popup',
size: { width: 300, height: 250 },
});
document.getElementById('banner-slot')!.appendChild(element);Refreshable Ad in Side Panel
import { createManagedRefreshableAd } from '@playanext/playa-yield-sdk';
await createManagedRefreshableAd({
container: '#ad-slot',
placement: 'sidepanel',
size: { width: 300, height: 250 },
});Multiple Ad Placements
import { createAd } from '@playanext/playa-yield-sdk';
const [ad1, ad2] = await Promise.all([
createAd({ placement: 'popup', size: { width: 300, height: 250 } }),
createAd({ placement: 'popup', size: { width: 320, height: 50 } }),
]);
document.getElementById('ad-slot-1')!.appendChild(ad1.element);
document.getElementById('ad-slot-2')!.appendChild(ad2.element);Custom Styling
import { createAd } from '@playanext/playa-yield-sdk';
const { element } = await createAd({
placement: 'popup',
size: { width: 300, height: 250 },
});
element.style.borderRadius = '8px';
element.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
element.style.margin = '20px auto';
document.getElementById('ad-slot')!.appendChild(element);Test Mode
Use test mode during development by using your test API key. The backend determines test vs production based on the API key.
initializePlayaYield({
apiKey: 'dev_test_key',
// Optional: point to a dedicated staging API
// baseUrl: 'https://your-test-host.example'
});What you get in test mode:
- Requests are tagged as test-mode server-side via the API key
- Safe separation between test and production analytics
- Real integration testing for placement, rendering, and tracking
- Optional custom
baseUrlfor dedicated staging environments
Chrome Web Store Compliance
Extensions integrating the PlayaYield SDK should include disclosure language to ensure Chrome Web Store approval.
Suggested Store Description Language
Our extension provides ads within the extension interface,
including in the popup, the side panel, and/or other
internal extension pages.Suggested Privacy Policy Language
This extension may display advertisements provided by third-party
partners, including PlayaYield. To deliver and measure advertising,
limited technical information such as IP address, device type,
browser type, and interaction data may be transmitted to advertising
partners. For more information, see PlayaYield's Privacy Policy:
https://www.playayield.com/privacyTracking & Privacy
PlayaYield handles all tracking automatically — no additional code required.
- Impressions — Tracked when the ad is at least 50% visible in the viewport via
IntersectionObserver - Clicks — Tracked automatically before opening the destination URL
- Session Management — Refreshable ads enforce per-session impression limits with rolling window tracking
Privacy:
- No personal data collection or third-party cookies
- Ads only appear in extension UI (popup, side panel, internal pages)
- No injection into user-facing websites
- Chrome Web Store compliant
Error Handling
The SDK throws typed errors that extend PlayaYieldError. Always wrap ad requests in try-catch blocks.
import { createAd } from '@playanext/playa-yield-sdk';
try {
const { element } = await createAd({
placement: 'popup',
size: { width: 300, height: 250 },
});
document.getElementById('ad-slot')!.appendChild(element);
} catch (error) {
if (error instanceof Error) {
switch (error.name) {
case 'ConfigError':
// SDK not initialized, missing params, or invalid config
console.error('Configuration error:', error.message);
break;
case 'NetworkError':
// Request failed, timeout, or server error
console.error('Network error:', error.message);
break;
default:
console.error('Unexpected error:', error);
}
}
}| Error Class | Code | Common Causes |
| ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| ConfigError | CONFIG_ERROR | Missing apiKey, missing placement / size, calling createAd() before initializePlayaYield(), unsupported ad size, content script context |
| NetworkError | NETWORK_ERROR | No internet, server timeout, invalid API key |
| PlayaYieldError | (base class) | All SDK errors extend this — includes code and optional details properties |
Build Output
The SDK is built with tsup and outputs:
| Format | File |
| ------ | --------------- |
| ESM | dist/sdk.mjs |
| CJS | dist/sdk.js |
| Types | dist/sdk.d.ts |
All formats are tree-shakeable and optimized for minimal bundle size.
Live Example
See the example/ directory for a complete working Chrome extension that demonstrates background service worker setup, popup ad display, error handling, and modern UI styling.
cd example
npm install
npm run buildThen load the example/ directory as an unpacked extension in Chrome.
A production example is also available on the Chrome Web Store:
Timezone Freedom — A Chrome Web Store-approved extension using PlayaYield in production.
Support
- Documentation — playayield.com/docs
- Issues — GitHub Issues
- Email — [email protected]
License
MIT © PlayaYield
