Skip to main content

Placement Events Listener

info

Event-Driven System: The Teads React Native SDK uses a comprehensive event system through TeadsAdPlacementHandler to manage placement interactions, height changes, and user engagement.

Overview

The Teads React Native SDK provides an event-driven system for managing placement events through the TeadsAdPlacementHandler interface. This handler allows you to:

  • Track placement height changes for dynamic sizing
  • Handle user interactions (clicks on ads and organic content)
  • Monitor widget events and custom data
  • Implement custom navigation and analytics

TeadsAdPlacementHandler Interface

The TeadsAdPlacementHandler interface defines four optional event handler methods:

interface TeadsAdPlacementHandler {
onHeightChange?: (newHeight: number) => void;
onRecClick?: (url: string) => void;
onOrganicClick?: (url: string) => void;
onWidgetEvent?: (eventName: string, data: { [key: string]: any }) => void;
}

All methods are optional - implement only the events you need to handle.

Event Types

onHeightChange

Called when the placement height changes. This is essential for dynamic ad sizing.

Event Payload:

  • newHeight: number - The new height in pixels

When it fires:

  • When an ad loads and its dimensions are determined
  • When ad content changes and requires resizing
  • For Feed Placements: When recommendations load
  • For Media Placements: When video ad dimensions are calculated

Example:

import { TeadsAdPlacementFeed, type TeadsAdPlacementHandler } from 'teads-react-native';

const handler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
console.log(`Placement height changed to ${newHeight}px`);

// The component automatically adjusts its height
// You can use this for analytics or UI updates
analytics.track('ad_height_changed', {
height: newHeight,
timestamp: Date.now(),
});
},
};

<TeadsAdPlacementFeed
widgetId="MB_1"
widgetIndex={0}
articleUrl="https://example.com/article/123"
partnerKey="YOUR_PARTNER_KEY"
handler={handler}
/>

onRecClick

Called when a user clicks on a paid recommendation or ad.

Event Payload:

  • url: string - The URL of the clicked recommendation/ad

When it fires:

  • User taps on a paid recommendation (Feed Placement)
  • User taps on a video ad (Media Placement)

Default Behavior:

  • Feed Placement: SDK automatically opens the URL
  • Media Placement: SDK automatically opens the URL outside the app
Do not open the URL manually

The SDK automatically handles opening the click URL. Do not implement URL navigation in this event handler — doing so will result in the browser opening twice. Use this event only for tracking/analytics purposes.

Example:

const handler: TeadsAdPlacementHandler = {
onRecClick: (url) => {
console.log('Ad/recommendation clicked:', url);

// Track click for analytics
analytics.track('ad_clicked', {
url: url,
placement: 'feed',
timestamp: Date.now(),
});
},
};

onOrganicClick

Called when a user clicks on organic (non-paid) content.

Event Payload:

  • url: string - The URL of the clicked organic content

When it fires:

  • User taps on organic content in Feed Placement
  • Typically not fired for Media Placement (video ads)

Default Behavior:

  • No automatic navigation - you should handle navigation yourself

Example:

import { useNavigation } from '@react-navigation/native';

const ArticleScreen = () => {
const navigation = useNavigation();

const handler: TeadsAdPlacementHandler = {
onOrganicClick: (url) => {
console.log('Organic content clicked:', url);

// Track for analytics
analytics.track('organic_clicked', { url });

// Navigate to organic content using your app's navigation
navigation.navigate('Article', { url });

// Or open in custom in-app browser
// InAppBrowser.open(url);
},
};

return (
<TeadsAdPlacementFeed
widgetId="MB_1"
widgetIndex={0}
articleUrl="https://example.com/article/123"
partnerKey="YOUR_PARTNER_KEY"
handler={handler}
/>
);
};

onWidgetEvent

Called for other widget events not covered by the specific handlers above.

Event Payload:

  • eventName: string - The name of the event
  • data: { [key: string]: any } - Additional event data

When it fires:

  • Custom widget events
  • Error events
  • Other placement-specific events

Example:

const handler: TeadsAdPlacementHandler = {
onWidgetEvent: (eventName, data) => {
console.log('Widget event:', eventName, data);

// Handle specific events
if (eventName === 'error') {
console.error('Placement error:', data);
// Handle error appropriately
} else if (eventName === 'impression') {
analytics.track('ad_impression', data);
} else if (eventName === 'viewability') {
analytics.track('ad_viewable', data);
}
},
};

Complete Handler Example

Here's a complete example implementing all event handlers:

import React from 'react';
import { View } from 'react-native';
import {
TeadsAdPlacementFeed,
type TeadsAdPlacementHandler,
} from 'teads-react-native';
import { useNavigation } from '@react-navigation/native';
import analytics from './analytics';

const ArticleScreen = () => {
const navigation = useNavigation();

const handler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
console.log(`Placement height: ${newHeight}px`);
analytics.track('ad_height_changed', { height: newHeight });
},

onRecClick: (url) => {
console.log('Ad clicked:', url);
analytics.track('ad_clicked', { url });
// SDK handles opening the URL
},

onOrganicClick: (url) => {
console.log('Organic clicked:', url);
analytics.track('organic_clicked', { url });
// Navigate using your app's navigation
navigation.navigate('Article', { url });
},

onWidgetEvent: (eventName, data) => {
console.log('Widget event:', eventName, data);

switch (eventName) {
case 'error':
console.error('Placement error:', data);
analytics.track('ad_error', data);
break;
case 'impression':
analytics.track('ad_impression', data);
break;
default:
analytics.track('widget_event', { eventName, data });
}
},
};

return (
<View>
<TeadsAdPlacementFeed
widgetId="MB_1"
widgetIndex={0}
articleUrl="https://example.com/article/123"
partnerKey="YOUR_PARTNER_KEY"
handler={handler}
/>
</View>
);
};

Handler for Multiple Placements

You can use the same handler for multiple placements or create separate handlers:

// Shared handler
const sharedHandler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
console.log('Height changed:', newHeight);
},
onRecClick: (url) => {
console.log('Clicked:', url);
},
};

// Or separate handlers
const feedHandler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
console.log('Feed height:', newHeight);
},
};

const mediaHandler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
console.log('Media height:', newHeight);
},
};

// Usage
<TeadsAdPlacementFeed handler={feedHandler} {...feedProps} />
<TeadsAdPlacementMedia handler={mediaHandler} {...mediaProps} />

Event Handling Best Practices

1. Always Handle Height Changes

Height changes are critical for proper layout:

const handler: TeadsAdPlacementHandler = {
onHeightChange: (newHeight) => {
// Component automatically adjusts, but you can track it
console.log('Height updated:', newHeight);
},
};

2. Implement Analytics Tracking

Track user interactions for analytics:

const handler: TeadsAdPlacementHandler = {
onRecClick: (url) => {
analytics.track('ad_clicked', {
url,
placement: 'feed',
timestamp: Date.now(),
});
},
onOrganicClick: (url) => {
analytics.track('organic_clicked', {
url,
placement: 'feed',
timestamp: Date.now(),
});
},
};

3. Handle Errors Gracefully

Monitor error events:

const handler: TeadsAdPlacementHandler = {
onWidgetEvent: (eventName, data) => {
if (eventName === 'error') {
console.error('Placement error:', data);
// Show user-friendly error message or fallback
}
},
};

4. Clean Up Handlers

The SDK automatically cleans up event listeners when components unmount. However, if you're using refs or external handlers:

import { useRef, useEffect } from 'react';

const ArticleScreen = () => {
const handlerRef = useRef<TeadsAdPlacementHandler>({
onHeightChange: (newHeight) => {
// Handler implementation
},
});

// Handler is automatically cleaned up
return (
<TeadsAdPlacementFeed
handler={handlerRef.current}
{...props}
/>
);
};

Event Payload Reference

Height Change Event

onHeightChange(newHeight: number)
  • newHeight: Height in pixels (number)

Click Events

onRecClick(url: string)
onOrganicClick(url: string)
  • url: The URL of the clicked item (string)

Widget Event

onWidgetEvent(eventName: string, data: { [key: string]: any })
  • eventName: Name of the event (string)
  • data: Additional event data (object with string keys and any values)

Platform-Specific Notes

iOS

  • Events are delivered through native bridge
  • Height changes are automatically applied to the component
  • Click handling respects iOS navigation patterns

Android

  • Events are delivered through native bridge
  • Height changes are automatically applied to the component
  • Click handling respects Android navigation patterns

Troubleshooting

Events Not Firing

  • Verify the handler is passed correctly to the component
  • Check that the component is mounted and visible
  • Verify placement is loading correctly
  • Check console for error messages

Height Changes Not Working

  • Ensure the component is in a ScrollView or similar container
  • Verify the handler's onHeightChange is implemented
  • Check that the placement is loading successfully

Clicks Not Working

  • Verify handler methods are implemented
  • Check that URLs are valid
  • Ensure the placement is interactive (not blocked by other views)

Next Steps


tip

Pro Tip: Always implement at least onHeightChange to ensure your layout adapts correctly to dynamic ad sizes. This is especially important for Feed Placements.