How the Genuin SDK places ads in a feed
Learn how a Genuin feed turns a monetization preset into ad slots and in-stream breaks, which sources fill a slot, and what happens when none can.
Ads in a Genuin embed or placement aren't positioned by code in your app. Genuin's feed service reads the monetization preset, a set of ad rules your team saves in Brand Control Center. It builds each page of the feed with the ads already in it. The SDK renders what arrives: it walks each ad slot's sources in order, plays in-stream ad breaks, and falls back to a house video when no ad fills.
This page explains that mechanism for the Android and iOS SDKs 2.1.5 and the Web SDK 2.0.6. The React Native SDK 3.0.3 runs the native 2.1.5 SDKs, so it behaves like them. There's no ad code to write: you add an embed or a placement as the integration guides describe, and the preset decides the rest.
Note: The tag-driven IAB units of the iAB Standard Size Experience SDK don't read presets. Each unit is filled from its own tag configuration; see Add iAB Standard Size Experiences to an Android app and Add iAB Standard Size Experiences to an iOS app.
How an ad reaches the screen
- The SDK loads the embed or placement. It calls
GET /goservices/embed?id=orGET /goservices/placement?placement_id=. The response carries the assigned preset asmonetize_presetand, during a takeover, asponsorship_id. - The SDK requests a page of the feed. Embeds, placements, standard walls, and the home feed all post to
/goservices/feed/v1/home. The body names the embed or placement and, after the first page, addspage_session,last_video_id, andlast_video_count. - The feed service resolves the preset for that embed or placement and picks the settings for the requesting platform.
- It computes positions. In-feed ad slots go at fixed positions in the feed, and in-stream breaks go on selected videos.
- It fills each slot. A slot becomes a Partnered Post when one is servable. Otherwise it lists programmatic sources in priority order, with a house video as the last resort.
- It returns up to 10 items, ads included.
- The SDK renders the page. It plays the videos, walks each slot's sources, and plays in-stream breaks through Google Interactive Media Ads (IMA).
The SDK never computes ad positions itself. None of the three SDKs reads Start Slot, Repeat Frequency, or the priority order; the feed service applies them before the page leaves the server.
How the feed finds its preset
Presets live in Brand Control Center under Settings > Ad Configuration > Presets. An embed or placement belongs to one preset at a time; assigning it to a second preset removes it from the first. On every feed request, the feed service looks for a preset in this order:
- The embed or placement. It takes the newest active preset that lists the embed or placement, or that applies to all of them.
- The brand feed. A request without an embed or a placement, such as the app home feed, uses the brand's Global Brand Feed configuration. Brand Control Center lists it first, with a globe icon.
- No preset. The feed carries no in-feed slots and no in-stream breaks.
A preset is active while one of its platforms has in-feed ads, in-stream ads, or Partnered Takeover turned on and has at least one embed or placement selected. Brand Control Center sets the flag when you save.
Which platform's settings apply
A preset stores settings for four platforms: Web, Mobile Web, iOS, and Android. Under Select environment to show ads, Global saves one set of settings for all four. Custom settings opens a tab per platform, and each tab is saved on its own.
The feed service decides the platform from the HTTP request:
| Request comes from | Settings used with Custom settings |
|---|---|
| A browser, desktop or mobile (the request carries a Sec-Fetch-Site header) | Web |
| A client whose user agent contains okhttp: the Android SDK and React Native on Android | Android |
| Any other client: the iOS SDK and React Native on iOS | iOS |
With Global, every request gets the same settings. The Mobile Web tab is saved but never used, because the feed service detects a mobile browser as Web.
How fast a change reaches the feed
The feed service caches each preset for 24 hours and keeps an in-process copy for 5 minutes. Brand Control Center evicts the 24-hour copy when you save, so an edit reaches new feed requests within about 5 minutes. The link from an embed or placement to its preset is cached separately for up to 24 hours.
A page that's already loaded keeps the ads it received; new positions apply from the next feed request. Android and iOS read monetize_preset once, when the embed or placement loads, so a change to Duration or Ad Aspect Ratio applies the next time it loads.
Preset fields
Every field below sits in the preset editor at Settings > Ad Configuration > Presets, then the preset name or New Preset. "Server" means the feed service applies the field; an SDK name means the SDK reads it on the device.
| Field | Brand Control Center label | Default | Values | Read by and effect |
|---|---|---|---|---|
| infeed.is_active | In-Feed Configuration switch | On | On, off | Server. Turns in-feed ad slots on. Brand Control Center refuses to save it on until the brand has at least one house ad. |
| infeed.start_from | In-Feed Configuration > Start Slot | 2 | 1 to 10 | Server. Position of the first ad slot, counted from 1, ads included. |
| infeed.swipe_freq | In-Feed Configuration > Repeat Frequency | 2 | 1 to 10 | Server. Distance between ad slots, in feed positions. |
| infeed.ad_types | In-Feed Configuration > Ad Types & Priority | Partnered Post and Video Ads on | Drag to reorder, switch each on or off | Server. Which sources may fill a slot and in what order. House (Fallback Content) is always on and always last. |
| ad_types house pre_roll, mid_roll, post_roll | Ad Types & Priority > Monetize fallback with In-Stream Ads, then Pre-roll, Mid-roll, Post-roll | Off | 0 or 1 each | Server. Adds in-stream breaks to the house video of an ad slot. |
| instream.is_active | In-Stream Ads switch | On | On, off | Server. Turns in-stream breaks on. |
| instream.start_from | In-Stream Ads > Start Content Video | 2 | 1 to 10 | Server. First content video that carries a break, counted from 1, ads excluded. |
| instream.swipe_freq | In-Stream Ads > Repeat Frequency | 2 | 1 to 10 | Server. A break every N content videos after the first. |
| instream.pre_roll, mid_roll, post_roll | No control. Brand Control Center saves 1 for all three. | 1 | 0 or 1 each | Server. Requests a pre-roll, a mid-roll, and a post-roll break. |
| infeed.display_duration, instream.display_duration | Controls > Duration | Off | On, off | Android and iOS. Shows the "Ad" countdown in the player. The Web SDK always shows it for in-stream ads. |
| infeed.aspect_ratio | Controls > Ad Aspect Ratio | Allow all aspect ratios | That, or Match video player ratio | Android and iOS. match_player sets the media shape of Google native ads to the player's. Video ads aren't affected. |
| infeed.ad_types duration | No control | 10 seconds | Seconds | Android and iOS. How long a native or banner ad stays on screen. |
| sponsored_takeover | Partnered Takeover switch | Off | On, off | Server. Lets an active takeover sponsorship replace the feed. |
| environment_type | Select environment to show ads | Global | Global, Custom settings | Server. Which platform's settings apply. |
| placements, embeds | Show ads on selected placements | None selected | Specific items, or all | Server. Which embeds and placements use this preset. |
| infeed.ad_event, instream.ad_event | Ad Events | Show ads in card view & in full screen | That, or Show ads only in full screen | Not read by any SDK, so Show ads only in full screen has no effect. |
| infeed.start_muted, instream.start_muted | Controls > Mute on Start | On for in-feed, off for in-stream | On, off | Not read. Ads follow the player's mute state. |
| infeed.allow_skip, instream.allow_skip | No control | On for in-feed, off for in-stream | On, off | Not read. No SDK draws its own skip button for video ads. |
Brand Control Center no longer offers Native Ads or Display Cards in the priority list. New presets save them switched off, so their slots carry video ads and the house video only. Presets saved before that change can still list them.
How ad slot positions are computed
In-feed ad slots sit at positions S, S + R, S + 2R, and so on, where S is Start Slot and R is Repeat Frequency. Positions count every item in the feed, ads included. A Repeat Frequency of 4 therefore leaves three content items between ads, and a Repeat Frequency of 1 makes every position from the start slot an ad slot.
Each page holds up to 10 items. When the SDK asks for the next page it reports last_video_count, the number of items it has received so far, ads included. The feed service plans slots for the next 40 positions from that count and keeps the 10 that fit the page.
In-stream breaks count content videos only. The count starts from the position of last_video_id in the feed, so ad slots never shift it. A break lands on content video S, S + R, and so on, using Start Content Video and the in-stream Repeat Frequency.
For example, take Start Slot 2 and Repeat Frequency 4 for in-feed, and Start Content Video 2 and Repeat Frequency 2 for in-stream. Page 1 opens with video 1, an ad slot, video 2 with a break, and video 3. It goes on with video 4 with a break, an ad slot, video 5, video 6 with a break, video 7, and an ad slot. Page 2 reports last_video_count 10, so its first ad slot is overall position 14, the fourth item on that page.
Note: Placements whose style has sections, and placements on the dynamic-sections algorithm, get no in-feed slots and no in-stream breaks.
How a slot is filled
For each slot position, the feed service decides what goes there before the page is sent:
- Partnered Post. If Partnered Post is on and the embed or placement has a servable post sponsorship, the slot becomes one of its posts. Consecutive slots rotate through the sponsorship's posts. The priority list isn't consulted, so a Partnered Post always wins over a programmatic ad.
- No house ad, no slot. Otherwise the slot needs a house ad. If the brand has none, the position is skipped and the content behind it moves up.
- Ad slot. The feed service sends one item of type
ads. It holds a house video, the programmatic candidates for each enabled ad type, and anorderlist.
A post sponsorship is servable when it's inside its dates, under its budget and its pacing allowance, and under its per-device frequency cap. Sponsorships whose targeting matches the request are tried before untargeted ones. Sponsorships are created under Grow > Off Site > Paid Partnership.
A house ad is a post marked House Ad under Manage > Posts, in the post's Monetization section. Slots rotate through the brand's house ads. A post can't be a house ad and part of a paid partnership at the same time.
The programmatic candidates come from Genuin's ad server configuration. For each media type, the feed service takes the first enabled configuration it finds on the embed or placement, then on the preset, then on the brand. Each provider in it joins a slot with a probability equal to its traffic percentage, so two slots can carry different providers. The order list holds the enabled programmatic types in their priority order, then house_ad.
{
"type": "ads",
"order": ["video_ad", "house_ad"],
"video_ad": [
{ "platform": "google", "ads_url": "https://pubads.g.doubleclick.net/gampad/ads?iu={{AD_UNIT}}", "cpm": 4.5 }
],
"house_ad": {
"video": { "uuid": "{{VIDEO_ID}}", "video": { "is_house_ad": true } },
"cpm": 0.00001
}
}How each SDK renders a slot
The SDK walks order from the first entry. Within a type, it tries each entry of the array in turn, and a type that runs out hands over to the next. The house video is loaded first and plays underneath while the walk runs, so the card shows a video while the sources are tried.
| Source | Android 2.1.5 | iOS 2.1.5 | Web 2.0.6 |
|---|---|---|---|
| video_ad from Google Ad Manager, Aniview, Infy, or Triton Digital | VAST through the Media3 IMA extension, preloaded on a second player and swapped in when it loads | VAST through Google IMA 3.22.1 | VAST through Genuin's ad script, gen_ad.min.js 1.0.0 |
| video_ad from Pangle | Full screen tries rewarded, interstitial, native, 300 × 250, then 320 × 50; cards try native, then the two banners. 10 seconds per format. | Same formats in the same order | Not supported; skipped |
| display_ad | Google Mobile Ads banner | Google Ad Manager banner | Google Ad Manager 300 × 250 banner; skipped in a slot smaller than 300 × 250 |
| native_ad | Google Mobile Ads native ad | Google Ad Manager native ad; skipped in a container under 140 points | Rendered by the ad script |
| house_ad | The house video keeps playing as a normal post | The house video plays as a normal post | The house video plays as a normal post |
When the house video carries its own in-stream ad tag, each SDK requests it once the walk reaches the house video. Android and iOS set no timeout of their own on IMA or Google Mobile Ads requests; the libraries' defaults apply.
The SDKs label what they render:
- Video ads show "Ad", the ad's position such as "1 of 2", and a countdown when Duration is on. The Web SDK adds no label of its own to in-feed ads.
- Partnered Posts show a "Sponsored" tag.
- House videos show no label to viewers. On Android, the post's owner, community leaders, and moderators see "Sponsored" on them.
- Native ads show an "Ad" pill in Genuin's native layout, and Pangle ads carry Pangle's own badge.
How in-stream breaks play
For a content video that gets a break, the feed service adds video.ads_config.ads_url. That's a VMAP (Video Multiple Ad Playlist) URL from the first video provider, among those drawn for the video, that has one configured. It asks for a pre-roll, a mid-roll, and a post-roll, and the ad server decides how many ads each break holds. Aniview and Infy get the mid-roll at half the video's duration; Google Ad Manager gets the rule pre_mid_post and the video's length. If no drawn provider has a VMAP URL, the video gets no break and plays as content.
| Android 2.1.5 | iOS 2.1.5 | Web 2.0.6 | |
|---|---|---|---|
| Player | Media3 with the IMA extension | Google IMA, breaks started as each is ready | The Genuin player with Google IMA, breaks scheduled by IMA |
| Skip button | IMA's own, when the VAST creative is skippable | None; IMA's interface is turned off | None drawn by the Genuin player |
| Sound | Follows the player's mute button | Follows the viewer's mute setting, muted until they unmute | Follows the player's mute state |
| On an ad error | Content resumes | Content resumes | Content resumes |
Partnered Takeover
A takeover replaces the feed with a sponsor's posts. It runs when the preset's Partnered Takeover is on for the platform and the embed or placement has an active takeover sponsorship:
- The embed or placement details include
sponsorship_idandcpm_rate. - The SDK sends that id with every feed request for the embed or placement. On the web, the
sponsorship_idoption ofinitnames the sponsorships the embed may ask for. - The feed service builds each page from the sponsorship's posts. With Allow other content to appear after takeover on and 10 posts or fewer, every page starts with them and regular content fills the rest. Otherwise every page holds 10 sponsored posts, repeating, and no regular content.
A takeover page carries no in-feed slots and no in-stream breaks. Takeover posts show the "Sponsored" tag. When the sponsorship ends or spends its budget, the feed service ignores its id and the feed returns to normal, ads included.
When a slot can't be filled
| Situation | What the viewer sees | What to check |
|---|---|---|
| The embed or placement has no active preset | Content only, no ads | The preset lists the embed or placement, and in-feed or in-stream ads are on for the platform |
| The brand has no house ad | The slot is skipped and content moves up | Mark at least one post as a house ad |
| No programmatic source fills | The house video, with no ad label | The ad server configuration for the media type, and its traffic percentages |
| A Pangle or Google Mobile Ads source has no fill | The SDK moves to the next source | The ad unit ids in the ad server configuration |
| An in-stream break fails | The content video starts or resumes | The VMAP URL of the video provider |
| The preset is on, but the platform shows no ads | Content only | With Custom settings, the tab for that platform. Mobile browsers use the Web tab. |
| Placement shows no ads | Content only | Whether the placement's style uses sections |
Platform differences
| Android 2.1.5 | iOS 2.1.5 | Web 2.0.6 | |
|---|---|---|---|
| Preset sub-object read on the device | android | ios, or the whole object | None |
| last_video_count counts | Posts, ad slots, and Partnered Posts received | Posts, ad slots, and Partnered Posts received | Every item received, including a start video the page opened with |
| In-stream ads when a video loops | Requested again only when the brand's in_video_stream ad setting is on | Requested again only when the brand's in_video_stream ad setting is on | Requested again on every loop |
| Ad Viewable Impression event | 2 seconds after the ad renders, while its container is visible | 2 seconds after the ad renders | Not sent; Ad Impression comes from IMA and the ad script |
The Flutter SDK 1.0.1 pins the Android SDK 1.1.9.3, which requests the older /goservices/feed/embed/home endpoint. That endpoint ignores presets, so Flutter apps on Android get no in-feed ad slots and no preset-driven in-stream breaks.
Limits
- Server-side only: You can't change ad positions, priority, or sources from SDK code. Every rule comes from the preset.
- Ranges: Start Slot, Start Content Video, and both Repeat Frequency fields accept 1 to 10.
- Page size: Each feed page holds up to 10 items, ads included.
- Mobile Web: The Mobile Web tab of a Custom settings preset isn't applied; mobile browsers get the Web settings.
- Unused controls: Ad Events and Mute on Start are saved but no SDK reads them.
- Caching: Preset edits take up to 5 minutes to reach feeds. Moving an embed or placement to another preset can take up to 24 hours.
- Sections: Placements with sections show no preset ads.
- IAB units: iAB Standard Size Experience SDK tags ignore presets.

