Developers/Ad ManagementBeta
Ad Management

Ad Management

Create and serve targeted promotional content, onboarding cards, announcements, and feature spotlights directly inside your app — managed from the Swake portal without a code deployment.

Overview

Swake Ad Management lets product and growth teams publish in-app content — banners, cards, interstitials, and more — from a central portal. Targeting rules, scheduling, and A/B variants are all configured without touching your app's code.

Feature announcements

Highlight new features to the right users at the right time.

Onboarding flows

Guide new users with sequential in-app cards and tips.

Upsell banners

Promote upgrades to free-tier users with conversion-focused copy.

Promotional campaigns

Run time-limited offers with start and end date scheduling.

Key capabilities:

Rich ad definitionsImage, text, CTA, and full HTML ad types.
Targeting rulesDevice type, user segment, and A/B variant matching.
Priority-based servingHighest-priority non-expired ad wins for a placement.
Version historyEvery definition change is snapshotted; roll back at any time.
Real-time togglingActivate or deactivate ads instantly — no app deploy required.
Impression trackingSDK reports impressions for analytics.

Creating Ads in the Portal

All ad management happens inside your project in the Swake portal. No API calls or code changes are needed to create or update ads.

StepAction
1Go to your project in the Swake portal.
2Navigate to Ads in the project sidebar.
3Click New Ad.
4Fill in: Name, Ad Type, Campaign (optional), Priority, Start/End dates.
5Design your ad content in the Definition JSON editor or use the visual editor.
6Set targeting rules: device type, user segment, and A/B variant.
7Click Save — the ad is created as inactive.
8Toggle Active to start serving the ad immediately.

Ads can be duplicated from the overflow menu — the copy gets a "(copy)" name suffix and starts as inactive. Full version history is preserved for every ad.


Ad Types & Formats

Choose the format that best fits your content and placement. Each type has its own definition_json schema.

BannerAnnouncements

Horizontal banner displayed at the top or bottom of the screen. Slim footprint, always visible.

CardFeature spotlights

Full-width card with image, title, body text, and a CTA button. Great for rich content.

InterstitialMajor announcements

Full-screen overlay shown at natural breakpoints. High impact, use sparingly.

InlineNative promotions

Embedded in a list or feed at a specified index. Feels native to the surrounding content.

HTMLBranded campaigns

Custom HTML/CSS with full design control. Ideal for rich, pixel-perfect branded content.


Ad Definition JSON

The ad content is stored as a definition_json blob validated by Zod on the API. Different ad types have different schemas.

Card

json
{
  "type": "card",
  "title": "New Feature: Dark Mode",
  "body": "You can now switch to dark mode in Settings → Appearance.",
  "imageUrl": "https://cdn.example.com/dark-mode-preview.png",
  "imageAlt": "Dark mode preview",
  "cta": {
    "label": "Try it now",
    "action": "navigate",
    "url": "settings/appearance"
  },
  "dismissible": true,
  "campaign": "q1-feature-launch"
}

Banner

json
{
  "type": "banner",
  "text": "🎉 Version 2.0 is here — see what's new",
  "cta": {
    "label": "Learn more",
    "action": "open_url",
    "url": "https://yourapp.com/changelog"
  },
  "backgroundColor": "#0f172a",
  "textColor": "#ffffff",
  "position": "top"
}

HTML

json
{
  "type": "html",
  "html": "<div style='padding: 16px; background: #f0fdf4;'>...</div>",
  "height": 120
}

CTA action types

ActionBehaviour
navigatePush a route inside the app (relative path).
open_urlOpen an external URL in the system browser.
dismissClose the ad without navigating anywhere.
custom_eventFire a named custom event for your analytics layer.

Targeting & Scheduling

Ads are only served to users that match all configured targeting rules. When multiple ads match the same placement, the one with the highest priority wins.

Device type

Target mobile, tablet, or desktop. Pass device_type in the SDK request.

mobiletabletdesktop
User segment

Comma-separated segment IDs created in Users → Segments. Only matched users see the ad.

Date range

ISO 8601 start_date and end_date. The ad is only served within this window.

Priority

Integer — higher number wins. When multiple ads match, the highest-priority active ad is returned.

Active flag

Global on/off toggle. Inactive ads never serve regardless of all other targeting rules.

A/B variant

Optional string key passed by the SDK to select a specific variant of a placement.

The SDK endpoint returns HTTP 204 when no ad matches the targeting rules. Always handle the no-ad case gracefully in your UI.


A/B Testing

Run controlled experiments by creating two ads with the same placement ID but different ab_variant values. The SDK passes the variant key at fetch time and receives only the matching ad.

StepAction
1Create Ad A with placement "home-banner" and ab_variant "control".
2Create Ad B with placement "home-banner" and ab_variant "treatment".
3Assign your users to variants in your app (e.g., via a feature flag service).
4Pass abVariant when fetching the ad from the SDK.
5Compare impression and conversion rates per variant in your analytics.
typescript
// SDK fetches ad for a specific A/B variant
const ad = await Swake.getAd('home-banner', {
  abVariant: userVariant, // 'control' | 'treatment'
});

Swake does not assign users to variants — that is handled by your own experimentation layer. Swake only serves the ad matching the variant you pass.


Version History

Every time definition_json changes, Swake automatically creates a new version snapshot. Metadata-only changes (name, active toggle, targeting) do not create a new version.

CapabilityDetails
View historyAds → select ad → History tab in the portal.
RollbackClick any past version to restore its definition_json as the current content.
Versions availableLast 10 version snapshots stored per ad.
API accessGET /v1/portal/ads/:id/versions/:version returns the full snapshot JSON.

SDK Integration

The SDK fetches and renders ads automatically using placement components, or you can fetch them manually and render with your own UI. Both patterns are supported across the React Native and Web SDKs.

Auto-serving (recommended)

Declare placements in Swake.init() and drop <AdPlacement> components anywhere in your UI. The SDK handles fetching, caching, and rendering.

Manual fetch

Call Swake.getAd(placementId) directly and render ad.definitionJson yourself for full UI control.


React Native

Install the React Native SDK and declare your ad placements during initialisation.

Auto-serving (recommended)

typescript
import Swake from '@swake/react-native';

// In Swake.init() — enable ad auto-serving
Swake.init({
  apiKey: 'ep_live_...',
  ads: {
    enabled: true,
    // Define placements
    placements: ['home-banner', 'dashboard-card'],
  },
});

Drop <AdPlacement> anywhere in your component tree. It renders the highest-priority active ad for the given placement ID.

tsx
import { AdPlacement } from '@swake/react-native';

// Renders the highest-priority active ad for this placement
<AdPlacement
  id="home-banner"
  onImpression={(ad) => console.log('Ad shown:', ad.id)}
  onCtaTap={(ad, cta) => console.log('CTA tapped:', cta.action)}
  onDismiss={(ad) => console.log('Ad dismissed:', ad.id)}
/>

Manual fetch

Fetch the ad imperatively and render the definitionJson with your own components.

typescript
const ad = await Swake.getAd('home-banner');
if (ad) {
  // Render ad.definitionJson yourself
  console.log(ad.definitionJson.type); // 'card'
  await Swake.trackImpression(ad.id);
}

Web SDK

Use @swake/web to mount placements in any container element or fetch ads manually.

typescript
import Swake from '@swake/web';

// Mount an ad placement
Swake.mountAdPlacement('home-banner', {
  container: document.getElementById('ad-container'),
  onImpression: (ad) => analytics.track('ad_shown', { adId: ad.id }),
  onCtaClick: (ad, cta) => {
    if (cta.action === 'navigate') router.push(cta.url);
  },
});

// Or fetch manually
const ad = await Swake.getAd('home-banner', {
  deviceType: 'desktop',
  userSegment: ['premium-users'],
});

The Web SDK renders ads inside a Shadow DOM to prevent CSS leakage. HTML ads have access to the full DOM inside their shadow root.


API Reference

SDK endpoints authenticate via X-API-Key. Portal endpoints require a valid JWT session cookie.

MethodPathDescriptionAuth
GET/v1/sdk/ads/:placementIdServe highest-priority ad for placementSDK
GET/v1/portal/projects/:projectId/adsList project adsPortal
POST/v1/portal/projects/:projectId/adsCreate adPortal
GET/v1/portal/ads/:idAd detail with definition + version historyPortal
PATCH/v1/portal/ads/:idUpdate ad or toggle activePortal
POST/v1/portal/ads/:id/duplicateDuplicate ad (inactive copy)Portal
DELETE/v1/portal/ads/:idSoft-delete adPortal
GET/v1/portal/ads/:id/versions/:versionGet specific version snapshotPortal

GET /v1/sdk/ads/:placementId — query parameters

ParameterRequiredValuesDescription
device_typeYesmobile | tablet | desktopDevice type of the requesting client.
user_segmentNocomma-separated segment IDsUser segment IDs for targeting matching.
ab_variantNoany stringA/B variant key to select the matching ad variant.

HTTP 200 — returns ad definition + metadata with Cache-Control and ETag headers. Supports If-None-Match conditional requests for efficient polling.
HTTP 204 — no ad matched the targeting rules. Render nothing.
Rate limit: 100 requests/min per API key (separate bucket from other SDK endpoints).