Implementation Methods
Native ads allow you to display ads with custom UI that matches your appâs design.
| Method | Description | Recommended |
|---|
| Default Template | Use SDK-provided template | Quick implementation |
| Custom UI | Build your own UI | When design customization is needed |
Use the test unit ID in development: PUBLIC_TEST_UNIT_ID_NATIVE
Default Template
You can use the default template in the same way as banner ads. Images and text are automatically rendered in the SDK-provided template.
function NativeAd() {
return <div data-adrop-unit="YOUR_NATIVE_UNIT_ID" />;
}
The default template does not support advertiser profile sections. Use custom UI to display advertiser profiles.
Custom UI
1. Data Attributes Method
Add the data-adrop-render="custom" attribute and bind fields using data-adrop-native attributes on inner elements.
function CustomNativeAd() {
return (
<div
data-adrop-unit="YOUR_NATIVE_UNIT_ID"
data-adrop-render="custom"
data-adrop-entire-click="true"
className="native-ad"
>
{/* Advertiser Profile */}
<div className="ad-profile">
<img data-adrop-native="profile.displayLogo" alt="Advertiser" />
<span data-adrop-native="profile.displayName"></span>
</div>
{/* Ad Content */}
<h3 data-adrop-native="headline"></h3>
<img data-adrop-native="asset" alt="Ad" />
<p data-adrop-native="body"></p>
{/* Extra text items */}
<span data-adrop-native="extra.price"></span>
{/* CTA Button */}
<button data-adrop-native="callToAction"></button>
</div>
);
}
Data Attributes
Unit ID created in Ad Control Console
Set to custom for custom UI
Context ID for contextual targeting
Theme setting (light or dark)
Enable entire area click
false: Only text/images are clickable, clicking advertiser profile goes to profile link
true: Entire container is clickable, all clicks go to ad destination
2. renderAd Method
Use this when you want direct control over ad loading timing.
import { useEffect, useRef } from 'react';
import Adrop from '@adrop/ads-web-sdk';
function CustomNativeAd() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const adrop = Adrop.instance();
if (containerRef.current) {
adrop.renderAd(containerRef.current, {
unit: 'YOUR_NATIVE_UNIT_ID',
contextId: 'YOUR_CONTEXT_ID',
theme: 'light',
trackMode: 1, // Required for custom UI
isEntireClick: true // Enable entire area click
});
}
}, []);
return (
<div ref={containerRef} className="native-ad">
<div className="ad-profile">
<img data-adrop-native="profile.displayLogo" alt="Advertiser" />
<span data-adrop-native="profile.displayName"></span>
</div>
<h3 data-adrop-native="headline"></h3>
<img data-adrop-native="asset" alt="Ad" />
<p data-adrop-native="body"></p>
<button data-adrop-native="callToAction"></button>
</div>
);
}
renderAd Options
Unit ID created in Ad Control Console
User identifier (used to override SDK-level setting for individual placements)
Context ID for contextual targeting
Theme setting (light or dark)
Field Binding
Bind ad data to UI elements using the data-adrop-native attribute.
| Field | Description | Element Type |
|---|
profile.displayLogo | Advertiser logo URL | <img> |
profile.displayName | Advertiser name | Text |
headline | Ad title | Text |
body | Ad description | Text |
asset | Main image URL | <img> |
callToAction | CTA button text | Text |
extra.{key} | Extra text items | Text |
extra.{key} is the ID of extra text items set in Ad Control Console. It may be empty if not set as required.
To display advertiser profile (profile.displayLogo, profile.displayName), you must enable Show Advertiser Profile for that ad unit in Ad Control Console.
Ad Size
Custom UI size can be set freely.
| Type | Size Setting | Alignment |
|---|
| Direct Ads | Responsive support | Horizontal/Vertical center |
| Backfill Ads | Initial width matching, height required | Horizontal center |
Backfill ads request creatives matching the container size. Specify an appropriate size.
Fetching Data Only with requestAd
If you want complete control over the UI, you can fetch only the ad data using requestAd.
import { useState, useEffect } from 'react';
import Adrop from '@adrop/ads-web-sdk';
function NativeAd() {
const [adData, setAdData] = useState<AdData | null>(null);
useEffect(() => {
async function loadAd() {
const adrop = Adrop.instance();
const response = await adrop.requestAd({
unit: 'YOUR_NATIVE_UNIT_ID',
trackMode: 1
});
if (response.code === 0 && response.result) {
setAdData(response.result);
}
}
loadAd();
}, []);
if (!adData) return null;
return (
<div className="native-ad">
<div className="ad-header">
{adData.profile?.displayLogo && (
<img src={adData.profile.displayLogo} alt="Advertiser" />
)}
<span>{adData.profile?.displayName}</span>
</div>
<h3>{adData.headline}</h3>
{adData.asset && <img src={adData.asset} alt="Ad" />}
<p>{adData.body}</p>
<a href={adData.destinationURL} target="_blank" rel="noopener noreferrer">
{adData.callToAction}
</a>
</div>
);
}
When using requestAd, you must implement impression/click tracking yourself. Also, backfill ads are not supported with this method. We recommend using renderAd unless thereâs a special case.
AdropAdResponse
Return value of requestAd().
| Field | Type | Description |
|---|
code | number | Response code (0: success, 4000-4003: error) |
msg | string | Response message |
result | AdData | Ad data (only present on success) |
Ad data object. Event handlers also receive the same structure. See Reference > AdData for details.
| Field | Type | Description |
|---|
format | string | Ad format (banner, nativeAd, backfill) |
unit | string | Unit ID |
headline | string | Ad title |
body | string | Ad description |
callToAction | string | CTA button text |
asset | string | Main image URL |
destinationURL | string | Click destination URL |
profile.displayLogo | string | Advertiser logo URL |
profile.displayName | string | Advertiser name |
profile.link | string | Advertiser profile link |
extra | Record<string, string> | Extra text items |
Event Handling
import { useEffect, useRef } from 'react';
import Adrop from '@adrop/ads-web-sdk';
function NativeAd({ unitId }: { unitId: string }) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const adrop = Adrop.instance();
const filter = { unit: unitId };
const handleReceived = (unit: string, adData: any) => {
console.log('Ad received:', adData);
};
const handleNoFill = (unit: string) => {
console.warn('No ad available:', unit);
};
const handleFailed = (unit: string) => {
console.error('Ad failed:', unit);
};
const handleImpression = (unit: string) => {
console.log('Ad impression:', unit);
};
const handleClicked = (unit: string) => {
console.log('Ad clicked:', unit);
};
adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
adrop.on(Adrop.Events.AD_FAILED, handleFailed, filter);
adrop.on(Adrop.Events.AD_IMPRESSION, handleImpression, filter);
adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);
if (containerRef.current) {
adrop.renderAd(containerRef.current, {
unit: unitId,
trackMode: 1,
isEntireClick: true
});
}
return () => {
adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
adrop.off(Adrop.Events.AD_FAILED, handleFailed);
adrop.off(Adrop.Events.AD_IMPRESSION, handleImpression);
adrop.off(Adrop.Events.AD_CLICKED, handleClicked);
};
}, [unitId]);
return (
<div ref={containerRef} className="native-ad">
<div className="ad-profile">
<img data-adrop-native="profile.displayLogo" alt="Advertiser" />
<span data-adrop-native="profile.displayName"></span>
</div>
<h3 data-adrop-native="headline"></h3>
<img data-adrop-native="asset" alt="Ad" />
<p data-adrop-native="body"></p>
<button data-adrop-native="callToAction"></button>
</div>
);
}
Supported Events
| Event | Constant | Description |
|---|
| Ad Received | AD_RECEIVED | Ad request successful |
| No Ad | AD_NO_FILL | No direct ads available |
| Request Failed | AD_FAILED | Ad request failed |
| Impression | AD_IMPRESSION | Ad impression recorded |
| Click | AD_CLICKED | User clicked the ad |
| No Backfill | AD_BACKFILL_NO_FILL | No backfill ad available |
Backfill Ads
When backfill ads are enabled, they are automatically requested when no direct ads are available. You can distinguish ad types using adData.format.
import { useEffect, useRef } from 'react';
import Adrop from '@adrop/ads-web-sdk';
function NativeAd({ unitId }: { unitId: string }) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const adrop = Adrop.instance();
const filter = { unit: unitId };
// Ad received (direct or backfill)
const handleReceived = (unit: string, adData: any) => {
if (adData.format === 'backfill') {
console.log('Backfill ad loaded');
} else {
console.log('Direct ad loaded'); // 'nativeAd'
}
};
// No direct ad (backfill request starts)
const handleNoFill = (unit: string) => {
console.log('No direct ad available, requesting backfill...');
};
// No backfill ad either
const handleBackfillNoFill = (unit: string) => {
console.warn('No backfill ad available either');
// Hide ad area, etc.
};
adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
adrop.on(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill, filter);
if (containerRef.current) {
adrop.renderAd(containerRef.current, { unit: unitId });
}
return () => {
adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
adrop.off(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill);
};
}, [unitId]);
return (
<div ref={containerRef}>
<h3 data-adrop-native="headline"></h3>
<img data-adrop-native="asset" alt="Ad" />
<p data-adrop-native="body"></p>
<button data-adrop-native="callToAction"></button>
</div>
);
}
Development Environment Testing: If at least one ad unit connected to the app is Monetizing, backfill ad requests can be made from localhost. On unapproved domains, an AD_BACKFILL_NO_FILL event will be triggered.