npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@playanext/playa-yield-sdk

v1.3.0

Published

PlayaYield Chrome Extension Ad Monetization SDK for Manifest V3

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.

npm version Bundle Size TypeScript License: MIT


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

npm install @playanext/playa-yield-sdk

Package 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() or createManagedRefreshableAd() 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 MutationObserver to 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 baseUrl for 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/privacy

Tracking & 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 build

Then 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


License

MIT © PlayaYield