@action-x/ad-sdk
v0.1.13
Published
Zero-dependency ad SDK for ActionX
Readme
@action-x/ad-sdk Usage Guide
Zero-dependency ad SDK for AI conversations, supporting Vanilla JS, Vue, React, Next.js, and all frameworks.
Quick Start
Installation
npm install @action-x/ad-sdkMinimal Example
import { AdManager } from '@action-x/ad-sdk';
import '@action-x/ad-sdk/style.css';
const manager = new AdManager({
apiBaseUrl: 'https://network.actionx.top/api/v1',
apiKey: 'ak_your_api_key',
});
// Request ads after AI conversation completes
await manager.requestAds({
query: 'Recommend a Bluetooth headset',
response: 'AI response content...',
});
// Render ad
manager.render(document.getElementById('ad-container'));Core Concepts
1. AdManager Configuration
const manager = new AdManager({
apiBaseUrl: string; // Required: API endpoint
apiKey: string; // Required: API key
cardOption?: { // Optional: Card configuration
variant?: 'horizontal' | 'vertical' | 'compact'; // Layout style
count?: number; // Number of ads to request, default 1
};
enabled?: boolean; // Enable ads, default true
debug?: boolean; // Debug mode, default false
});2. Request Ads
// Simplified call (recommended)
await manager.requestAds({
query: string; // Required: User query
response: string; // Required: AI response content
});
// Full call
await manager.requestAds({
conversationContext: {
query: string;
response: string;
},
userContext?: {
sessionId?: string;
userId?: string;
}
});3. Render Ads
// Simplified call (renders action_card slot by default)
manager.render(
container: HTMLElement,
options?: {
adIndex?: number; // Ad index, default 0
variant?: string; // Layout variant
onClick?: (ad) => void; // Click callback
onImpression?: (ad) => void; // Impression callback
}
);
// Specify slot
manager.render(
slotId: string,
container: HTMLElement,
options?: { ... }
);4. Event Listeners
manager.on('adsUpdated', (slots) => {
console.log('Ad data updated');
});
manager.on('adsLoading', () => {
console.log('Requesting ads');
});
manager.on('adsError', (error) => {
console.warn('Ad request failed', error);
});
manager.on('adClicked', (adId, slotId) => {
console.log('Ad clicked', adId);
});
manager.on('adImpression', (adId, slotId) => {
console.log('Ad impression', adId);
});Framework Integration Examples
Vanilla JavaScript
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/@action-x/ad-sdk@latest/dist/style.css" />
</head>
<body>
<div id="ad-container"></div>
<script src="https://unpkg.com/@action-x/ad-sdk@latest/dist/index.umd.js"></script>
<script>
const { AdManager } = ActionXAdSDK;
const manager = new AdManager({
apiBaseUrl: 'https://network.actionx.top/api/v1',
apiKey: 'ak_your_api_key',
debug: false,
});
manager.on('adsUpdated', () => {
manager.render(document.getElementById('ad-container'));
});
// Call after conversation completes
function onChatComplete(query, response) {
manager.requestAds({ query, response });
}
</script>
</body>
</html>Vue 3
Install and import styles:
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import '@action-x/ad-sdk/style.css';
createApp(App).mount('#app');Create Composable:
// composables/useAdManager.ts
import { ref, shallowRef, onUnmounted } from 'vue';
import { AdManager } from '@action-x/ad-sdk';
export function useAdManager() {
const manager = shallowRef(
new AdManager({
apiBaseUrl: 'https://network.actionx.top/api/v1',
apiKey: 'ak_your_api_key',
debug: false,
})
);
const isLoading = ref(false);
const error = ref<Error | null>(null);
manager.value.on('adsLoading', () => {
isLoading.value = true;
error.value = null;
});
manager.value.on('adsUpdated', () => {
isLoading.value = false;
});
manager.value.on('adsError', (e) => {
isLoading.value = false;
error.value = e;
});
onUnmounted(() => manager.value.destroy());
async function requestAds(query: string, response: string) {
await manager.value.requestAds({ query, response });
}
return { manager, isLoading, error, requestAds };
}Use in component:
<template>
<div class="chat-response">
<div class="response-text">{{ responseText }}</div>
<div ref="adRef" class="ad-mount"></div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue';
import { useAdManager } from '@/composables/useAdManager';
const props = defineProps<{
query: string;
responseText: string;
isStreaming: boolean;
}>();
const adRef = ref<HTMLElement>();
const { manager, requestAds } = useAdManager();
watch(
() => props.isStreaming,
async (streaming) => {
if (!streaming && props.responseText) {
await requestAds(props.query, props.responseText);
await nextTick();
if (adRef.value) {
manager.value.render(adRef.value);
}
}
}
);
</script>React / Next.js
Import styles:
// Next.js App Router: app/layout.tsx
import '@action-x/ad-sdk/style.css';
export default function RootLayout({ children }) {
return <html><body>{children}</body></html>;
}
// Vite + React: src/main.tsx
import '@action-x/ad-sdk/style.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);Create Hook:
// hooks/useAdManager.ts
import { useEffect, useRef, useState, useCallback } from 'react';
import { AdManager } from '@action-x/ad-sdk';
export function useAdManager() {
const managerRef = useRef<AdManager | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const manager = new AdManager({
apiBaseUrl: 'https://network.actionx.top/api/v1',
apiKey: 'ak_your_api_key',
debug: false,
});
manager.on('adsLoading', () => setIsLoading(true));
manager.on('adsUpdated', () => {
setIsLoading(false);
setIsReady(true);
});
manager.on('adsError', (e) => {
setIsLoading(false);
setError(e);
});
managerRef.current = manager;
return () => manager.destroy();
}, []);
const requestAds = useCallback(async (query: string, response: string) => {
if (!managerRef.current) return;
await managerRef.current.requestAds({ query, response });
}, []);
return { manager: managerRef.current, isLoading, isReady, error, requestAds };
}Create Ad Component:
// components/AdCard.tsx
'use client';
import { useEffect, useRef } from 'react';
import type { AdManager } from '@action-x/ad-sdk';
interface AdCardProps {
manager: AdManager | null;
isReady: boolean;
className?: string;
}
export function AdCard({ manager, isReady, className }: AdCardProps) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!isReady || !manager || !containerRef.current) return;
manager.render(containerRef.current);
}, [isReady, manager]);
return <div ref={containerRef} className={className} />;
}Use in page:
// app/chat/page.tsx
'use client';
import { useState } from 'react';
import { useAdManager } from '@/hooks/useAdManager';
import { AdCard } from '@/components/AdCard';
export default function ChatPage() {
const [query, setQuery] = useState('');
const [response, setResponse] = useState('');
const [isStreaming, setIsStreaming] = useState(false);
const { manager, isReady, requestAds } = useAdManager();
const handleSend = async () => {
setIsStreaming(true);
const aiResponse = await fetchAIResponse(query);
setResponse(aiResponse);
setIsStreaming(false);
await requestAds(query, aiResponse);
};
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<button onClick={handleSend}>Send</button>
{response && (
<div>
<p>{response}</p>
<AdCard manager={manager} isReady={isReady} className="mt-4" />
</div>
)}
</div>
);
}Custom Styles
The SDK uses the ax-ad-* namespace. Override styles via CSS:
/* Custom CTA button */
.ax-ad-cta {
background-color: #7c3aed !important;
border-radius: 20px;
}
.ax-ad-cta:hover {
background-color: #6d28d9 !important;
}
/* Custom card style */
.ax-ad-card {
border: none;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
.ax-ad-card {
background: #1f2937;
border-color: #374151;
color: #f9fafb;
}
.ax-ad-title { color: #f9fafb; }
.ax-ad-body { color: #9ca3af; }
}
/* Hide on mobile */
@media (max-width: 640px) {
.ax-ad-card { display: none; }
}Debugging Tips
Enable Debug Logging
const manager = new AdManager({
apiBaseUrl: '...',
apiKey: '...',
debug: true, // Outputs detailed logs to console
});Check Ad Response
manager.on('adsUpdated', (slots) => {
console.log('Ad slots:', Object.keys(slots));
Object.entries(slots).forEach(([slotId, slot]) => {
console.log(`[${slotId}] Status:`, slot.status);
console.log(`[${slotId}] Ad count:`, slot.ads.length);
if (slot.status === 'no_fill') {
console.log(' → No fill (insufficient inventory or targeting mismatch)');
}
if (slot.status === 'error') {
console.error(' → Slot error:', slot.error);
}
});
});Common Issues
| Issue | Possible Cause | Solution |
|-------|---------------|----------|
| Empty ad container | render() called before requestAds() completes | Call render() inside adsUpdated event |
| Styles not applied | Forgot to import CSS | Ensure import '@action-x/ad-sdk/style.css' |
| Console 403 error | Invalid or missing apiKey | Check apiKey configuration |
| TypeScript type errors | Type definitions not generated | Run npm run build |
| Ad status 'no_fill' | No matching ads | Expected behavior, check manager.hasAds() before rendering |
| Clicks unresponsive | Container obscured | Check CSS z-index and pointer-events |
API Reference
AdManager
Constructor
new AdManager(config: AdManagerConfig)Methods
// Request ads
requestAds(context: { query: string; response: string }): Promise<AdResponseBatch>
requestAds(context: { conversationContext, userContext? }): Promise<AdResponseBatch>
// Render ads
render(container: HTMLElement, options?: RenderOptions): HTMLElement | null
render(slotId: string, container: HTMLElement, options?: RenderOptions): HTMLElement | null
// Check if ads available
hasAds(slotId: string): boolean
// Get ad data
getAds(slotId: string): any[]
getSlots(slotId?: string): Record<string, AdSlotResponse> | AdSlotResponse | undefined
// Destroy instance
destroy(): void
// Event listeners
on(event: string, handler: Function): void
off(event: string, handler: Function): voidEvents
adsLoading- Started requesting adsadsUpdated- Ad data updatedadsError- Request failedadClicked- Ad clickedadImpression- Ad impression
Version Info
- Current version:
0.1.12 - License: MIT
- Repository: GitHub
Support
For questions, contact ActionX support or submit an Issue.
