Skip to content

geniusrabbit/adview

Repository files navigation

AdView

Build Status TypeScript React License

AdView is a modern, type-safe React library for displaying and managing advertisements in web applications. It provides flexible components for multiple ad formats with built-in tracking, error handling, and both client-side and server-side rendering support.

Features

  • 🎯 Multiple Ad Formats: Support for banner, native, and proxy advertisements
  • 🔄 Dual Rendering: Both client-side and server-side rendering capabilities
  • 📊 Built-in Tracking: Automatic impression and click tracking
  • 🛡️ Type Safety: Full TypeScript support with comprehensive type definitions
  • 🎨 Customizable Styling: Flexible styling system for different ad formats
  • 🚀 Performance Optimized: Lazy loading and efficient bundle splitting
  • đź”§ Extensible: Plugin-based scraper system for data collection
  • ⚡ Next.js App Router: Full compatibility with Next.js 13+ App Router

Packages

This monorepo contains the following packages:

  • @adview/core: Core utilities, types, and shared functionality
  • @adview/react: React components and hooks for AdView
  • @adview/native: Vanilla JavaScript SDK for advertisement integration and rendering
  • @adview/popunder: Lightweight JavaScript library for popunder advertisements
  • @adview/react-popunder: React wrapper component for the PopUnder script

Table of Contents

Installation

Install the package using npm or yarn:

npm install @adview/react
yarn add @adview/react

Import Styles

AdView supports multiple import styles for different use cases:

Package-level imports (recommended)

// React components - namespace import
import * as AdView from '@adview/react';

Build all packages
// React components - named imports
import { Provider, Unit, Template, DefaultTemplate } from '@adview/react';

// Server components (for Next.js App Router)
import { Unit as ServerUnit } from '@adview/react/server';

Direct utility imports

// Core utilities (tree-shakable)
import { adViewFetcher, getResolveConfig } from '@adview/core/utils';

// TypeScript types
import { AdViewData, AdViewConfig } from '@adview/core/typings';

Benefits:

  • Tree-shaking: Import only what you need
  • Type safety: Full TypeScript support
  • Intellisense: Better IDE autocomplete
  • Future-proof: Ready for framework extensions (@adview/vue, @adview/angular)

Quick Start

Basic Usage

import * as AdView from '@adview/react';

function MyComponent() {
  return (
    <AdView.Unit
      unitId="your-ad-unit-id"
      srcURL="https://your-ad-server.com/ads/{<id>}"
      format="banner"
    />
  );
}

With Provider (Recommended)

import * as AdView from '@adview/react';

function App() {
  return (
    <AdView.Provider srcURL="https://your-ad-server.com/ads/{<id>}">
      <AdView.Unit unitId="header-banner" format="banner" />
      <AdView.Unit unitId="sidebar-native" format="native" />
    </AdView.Provider>
  );
}

Custom Rendering

import * as AdView from '@adview/react';

function CustomAd() {
  return (
    <AdView.Unit unitId="custom-ad" format="native">
      {({ data, state, error, onDefault }) => {
        if (state.isLoading) return <div>Loading ad...</div>;
        if (state.isError) return <div>Failed to load ad</div>;
        if (!data) return onDefault?.() || null;

        return (
          <div className="custom-ad">
            <h3>{data.fields?.title}</h3>
            <p>{data.fields?.description}</p>
          </div>
        );
      }}
    </AdView.Unit>
  );
}

Advanced Usage with Multiple Formats

import * as AdView from '@adview/react';

function AdvancedAd() {
  return (
    <AdView.Unit unitId="multi-format-ad" format={['native', 'banner', 'proxy']}>
      {/* Loading state for all formats */}
      <AdView.Template type="*" isLoading={true}>
        <div className="loading-placeholder">
          Loading ad...
        </div>
      </AdView.Template>

      {/* Banner ad template */}
      <AdView.Template type="banner">
        {({ data }) => {
          const mainAsset = data?.assets?.find(asset => asset.name === 'main');
          return (
            <div className="banner-ad">
              <a href={data?.url} target="_blank" rel="noopener">
                <img
                  src={mainAsset?.path}
                  alt={data?.fields?.title}
                  style={{ width: '100%', height: 'auto' }}
                />
              </a>
            </div>
          );
        }}
      </AdView.Template>

      {/* Native ad template */}
      <AdView.Template type="native">
        {({ data }) => {
          const mainAsset = data?.assets?.find(asset => asset.name === 'main');
          return (
            <div className="native-ad">
              <a href={data?.fields?.url} target="_blank" rel="noopener">
                <img src={mainAsset?.path} alt={data?.fields?.title} />
                <h3>{data?.fields?.title}</h3>
                <p>{data?.fields?.description}</p>
                <span>{data?.fields?.brandname}</span>
              </a>
            </div>
          );
        }}
      </AdView.Template>

      {/* Proxy template for iframe-based ads */}
      <AdView.ProxyTemplate className="proxy-ad-container" />

      {/* Fallback template */}
      <AdView.DefaultTemplate>
        <div className="fallback-ad">
          <iframe
            src="https://your-fallback-ad.com"
            width="100%"
            height="240"
            frameBorder="0"
          />
        </div>
      </AdView.DefaultTemplate>
    </AdView.Unit>
  );
}

API Reference

AdView.Unit

Main component for displaying advertisements.

Props

Prop Type Required Description
unitId string âś“ Unique identifier for the ad unit
format 'banner' | 'native' | 'proxy' | string[] âś— Ad format type or array of formats
srcURL string âś— Ad server URL template
onDefault () => ReactNode | ReactNode âś— Fallback content when no ad is available
children function | ReactElement âś— Custom render function or component

Load State

The component provides detailed loading states:

type AdLoadState = {
  isInitial: boolean;  // Initial state before loading
  isLoading: boolean;  // Currently fetching ad data
  isError: boolean;    // Error occurred during loading
  isComplete: boolean; // Loading completed (success or error)
};

AdView.Provider

Context provider for global configuration.

Provider Props

Prop Type Description
srcURL string Default ad server URL template
children ReactNode Child components

AdView.Template

Template component for custom ad rendering with specific ad types.

Template Props

Prop Type Description
type 'banner' | 'native' | 'proxy' | '*' Ad type for template matching. Use '*' for all types
isLoading boolean Only render when in loading state
isError boolean Only render when in error state
isComplete boolean Only render when loading is complete
children function Render function receiving ad data and state

AdView.ProxyTemplate

Pre-built template for proxy (iframe-based) ads.

ProxyTemplate Props

Prop Type Description
className string CSS class for the iframe container
style React.CSSProperties Inline styles for the iframe

ProxyTemplate Usage

<AdView.Unit unitId="proxy-ad">
  <AdView.ProxyTemplate className="ad-iframe" />
</AdView.Unit>

AdView.DefaultTemplate

Default fallback template when no ad data is available.

DefaultTemplate Usage

<AdView.Unit unitId="example">
  <AdView.DefaultTemplate>
    <div>No ad available</div>
  </AdView.DefaultTemplate>
</AdView.Unit>

Ad Formats

Banner Ads

Simple image-based advertisements:

<AdView.Unit unitId="banner-300x250" format="banner" />

Native Ads

Content-style ads with structured data:

<AdView.Unit unitId="native-article" format="native" />

Proxy Ads

Delegated rendering to external systems:

<AdView.Unit unitId="proxy-widget" format="proxy" />

Configuration

Environment Variables

# Default ad server URL
ADSERVER_AD_JSONP_REQUEST_URL=https://your-ad-server.com/ads/{<id>}

URL Template

The srcURL should contain {<id>} placeholder that will be replaced with the unitId:

https://ads.example.com/serve/{<id>}?format=json

Data Collection

The library automatically collects browser data for ad targeting:

  • Screen dimensions
  • Timestamp
  • Cache-busting tokens

You can extend data collection by adding custom scrapers:

import { pageScrapers } from '@adview/core/utils';

// Add custom scraper
pageScrapers.push(() => ({
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
}));

Tracking

Automatic Tracking

The library automatically handles:

  • Impression tracking: When ads become visible
  • Click tracking: When users interact with ads
  • View tracking: Custom view events

Manual Tracking

import { AdViewUnitTracking } from '@adview/react';

<AdViewUnitTracking
  impressions={['https://track.example.com/imp?id=123']}
  clicks={['https://track.example.com/click?id=123']}
  views={['https://track.example.com/view?id=123']}
>
  <YourAdComponent />
</AdViewUnitTracking>

Server-Side Rendering

For SSR applications, use the server-specific components:

import { Unit as ServerUnit } from '@adview/react/server';

// In your server component
function ServerPage() {
  return (
    <ServerUnit
      unitId="ssr-banner"
      srcURL="https://ads.example.com/serve/{<id>}"
    />
  );
}

Next.js App Router

Client Components

For interactive ads with loading states and user interactions, mark your component as a client component:

'use client';

import * as AdView from '@adview/react';

export default function ClientAdComponent() {
  return (
    <AdView.Provider srcURL="https://ads.example.com/serve/{<id>}">
      <AdView.Unit unitId="interactive-ad" format="native">
        {({ data, state, error }) => {
          if (state.isLoading) return <div>Loading...</div>;
          if (error) return <div>Error: {error.message}</div>;
          if (!data) return null;

          return (
            <div className="ad-content">
              <h3>{data.fields?.title}</h3>
              <p>{data.fields?.description}</p>
            </div>
          );
        }}
      </AdView.Unit>
    </AdView.Provider>
  );
}

Server Components

For static ads that don't require client-side interactivity:

import { Unit as ServerUnit } from '@adview/react/server';

export default function ServerAdComponent() {
  return (
    <ServerUnit
      unitId="static-banner"
      srcURL="https://ads.example.com/serve/{<id>}"
      format="banner"
    />
  );
}

Common Issues

Error: "Functions are not valid as a child of Client Components"

This occurs when using render functions in Server Components. Solution:

  1. Add 'use client' directive to your component
  2. Or use server-specific components from @adview/react/server

PopUnder Package

The @adview/popunder package provides a standalone JavaScript library for creating popunder advertisements. It's designed to be lightweight and work independently of the React components.

PopUnder Features

  • âś… Cross-browser compatibility (Chrome, Firefox, Safari, Edge, Opera)
  • âś… Mobile device support (iOS, Android, Windows Phone)
  • âś… AdBlock detection
  • âś… Cookie-based and click-based frequency control
  • âś… Flexible CSS selector targeting
  • âś… Customizable parameters and templates
  • âś… Built-in analytics and tracking

PopUnder Quick Start

<script
  type="text/javascript"
  src="./dist/popunder.js"
  data-ad-template="https://ads.example.com/{unitid}/redirect"
  data-ad-unitid="your_unit_id"
  data-ad-target="a"
  data-ad-every="1h30m"
  data-ad-every-direct="3"
  async
  defer
></script>

For detailed PopUnder documentation, see packages/popunder/README.md.

Development

Prerequisites

  • Node.js ≥ 18
  • npm or yarn

Setup

# Clone the repository
git clone https://github.com/geniusrabbit/adview.git
cd adview

# Install dependencies
npm install

# Build all packages
npm run build

# Start development mode
npm run dev

Package-specific Commands

PopUnder Package

# Development mode for popunder
npm run popunder:dev

# Build popunder package
npm run popunder:build

# Clean popunder build files
npm run popunder:clean

React PopUnder Package

# Development mode for react-popunder
npm run react-popunder:dev

# Build react-popunder package
npm run react-popunder:build

# Clean react-popunder build files
npm run react-popunder:clean

Core React Package

# Build all packages
npm run build

# Run linting
npm run lint

# Run tests
npm run test

Testing PopUnder

To test the PopUnder functionality:

# Navigate to popunder package
cd packages/popunder

# Serve test files locally
npx http-server . -p 8080

# Open browser and navigate to:
# http://localhost:8080/test.html

Scripts

npm run build          # Build all packages
npm run lint           # Run ESLint
npm run test           # Run tests
npm run version        # Version packages
npm run release        # Publish packages
npm run popunder:dev   # Development mode for popunder
npm run popunder:build # Build popunder package
npm run popunder:clean # Clean popunder build files

Publishing to npm

For detailed instructions on publishing packages to npm, see PUBLISHING.md.

Quick Publishing Commands

# Check packages are ready for publishing
npm run build
npm run lint
npm run test

# Login to npm (first time only)
npm login

# Publish all packages
npm run publish

# Or publish specific package
cd packages/popunder
npm publish

cd packages/react
npm publish

Version Management

# Check current versions
npm run version-check

# Bump versions
npm version patch   # or minor, major
npm version minor
npm version major

Automated Publishing with Tags

The repository includes GitHub Actions for automated publishing:

  1. Push a version tag to trigger publishing:

    git tag v1.0.1
    git push origin v1.0.1
  2. GitHub Actions automatically:

    • Builds all packages
    • Runs tests and linting
    • Publishes to npm registry
    • Creates GitHub release

CI/CD Workflows

Three GitHub Actions workflows are configured:

  • ci.yml: Runs tests, lint, build on PRs and pushes
  • publish.yml: Publishes packages when version tags are pushed
  • release.yml: Manages changeset-based releases on main branch

Creating New Framework Packages

To add support for new frameworks (Vue, Angular, etc.):

# Create new package structure
mkdir -p packages/vue
cd packages/vue

# Initialize package
npm init -y

# Install dependencies and implement
# ... implement Vue components ...

# Build and test
npm run build
npm publish --dry-run

Troubleshooting

PopUnder Issues

  1. PopUnder not showing: Check browser popup blockers, verify required attributes
  2. Frequency problems: Clear cookies/localStorage, check time format
  3. Mobile issues: Test on actual devices, verify touch events

Publishing Issues

Permission Errors

npm ERR! code E403
npm ERR! 403 Forbidden - PUT https://registry.npmjs.org/@adview%2freact

Solution: Ensure you have publishing permissions for the @adview scope.

Authentication Errors

npm ERR! code E401
npm ERR! 401 Unauthorized

Solution: Run npm login again.

Package Already Exists

npm ERR! code E409
npm ERR! Cannot publish over existing version

Solution: Increment version number in package.json.

Automated CI/CD Publishing

For automated publishing in CI/CD pipelines:

# Use npm token for authentication
echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc

# Build and publish
npm run build
npm run publish

React PopUnder Package

The @adview/react-popunder package provides a React wrapper component for the PopUnder script, allowing seamless integration into React applications.

React PopUnder Installation

npm install @adview/react-popunder

React PopUnder Usage

import { AdPopunder } from '@adview/react-popunder';

function MyComponent() {
  return (
    <AdPopunder
      unitId="your_unit_id"
      template="https://ads.example.com/{unitid}/redirect"
      target="a"
      every="1h30m"
      every-direct={3}
    />
  );
}

React PopUnder Build Configuration

The React PopUnder package uses tsup for building both ES modules and CommonJS versions:

  • ESM: dist/index.mjs - for modern bundlers
  • CJS: dist/index.cjs - for Node.js and older bundlers
  • Types: dist/index.d.ts - TypeScript declarations
# Development mode for react-popunder
npm run react-popunder:dev

# Build react-popunder package
npm run react-popunder:build

# Clean react-popunder build files
npm run react-popunder:clean

About

AdView is a lightweight package for managing and displaying advertisements on web platforms

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •