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

  1. The SDK loads the embed or placement. It calls GET /goservices/embed?id= or GET /goservices/placement?placement_id=. The response carries the assigned preset as monetize_preset and, during a takeover, a sponsorship_id.
  2. 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, adds page_session, last_video_id, and last_video_count.
  3. The feed service resolves the preset for that embed or placement and picks the settings for the requesting platform.
  4. It computes positions. In-feed ad slots go at fixed positions in the feed, and in-stream breaks go on selected videos.
  5. 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.
  6. It returns up to 10 items, ads included.
  7. 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:

  1. The embed or placement. It takes the newest active preset that lists the embed or placement, or that applies to all of them.
  2. 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.
  3. 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 fromSettings 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 AndroidAndroid
Any other client: the iOS SDK and React Native on iOSiOS

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.

FieldBrand Control Center labelDefaultValuesRead by and effect
infeed.is_activeIn-Feed Configuration switchOnOn, offServer. 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_fromIn-Feed Configuration > Start Slot21 to 10Server. Position of the first ad slot, counted from 1, ads included.
infeed.swipe_freqIn-Feed Configuration > Repeat Frequency21 to 10Server. Distance between ad slots, in feed positions.
infeed.ad_typesIn-Feed Configuration > Ad Types & PriorityPartnered Post and Video Ads onDrag to reorder, switch each on or offServer. 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_rollAd Types & Priority > Monetize fallback with In-Stream Ads, then Pre-roll, Mid-roll, Post-rollOff0 or 1 eachServer. Adds in-stream breaks to the house video of an ad slot.
instream.is_activeIn-Stream Ads switchOnOn, offServer. Turns in-stream breaks on.
instream.start_fromIn-Stream Ads > Start Content Video21 to 10Server. First content video that carries a break, counted from 1, ads excluded.
instream.swipe_freqIn-Stream Ads > Repeat Frequency21 to 10Server. A break every N content videos after the first.
instream.pre_roll, mid_roll, post_rollNo control. Brand Control Center saves 1 for all three.10 or 1 eachServer. Requests a pre-roll, a mid-roll, and a post-roll break.
infeed.display_duration, instream.display_durationControls > DurationOffOn, offAndroid and iOS. Shows the "Ad" countdown in the player. The Web SDK always shows it for in-stream ads.
infeed.aspect_ratioControls > Ad Aspect RatioAllow all aspect ratiosThat, or Match video player ratioAndroid and iOS. match_player sets the media shape of Google native ads to the player's. Video ads aren't affected.
infeed.ad_types durationNo control10 secondsSecondsAndroid and iOS. How long a native or banner ad stays on screen.
sponsored_takeoverPartnered Takeover switchOffOn, offServer. Lets an active takeover sponsorship replace the feed.
environment_typeSelect environment to show adsGlobalGlobal, Custom settingsServer. Which platform's settings apply.
placements, embedsShow ads on selected placementsNone selectedSpecific items, or allServer. Which embeds and placements use this preset.
infeed.ad_event, instream.ad_eventAd EventsShow ads in card view & in full screenThat, or Show ads only in full screenNot read by any SDK, so Show ads only in full screen has no effect.
infeed.start_muted, instream.start_mutedControls > Mute on StartOn for in-feed, off for in-streamOn, offNot read. Ads follow the player's mute state.
infeed.allow_skip, instream.allow_skipNo controlOn for in-feed, off for in-streamOn, offNot 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:

  1. 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.
  2. 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.
  3. 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 an order list.

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.

In-feed ad slot (abridged)
json
{
  "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.

SourceAndroid 2.1.5iOS 2.1.5Web 2.0.6
video_ad from Google Ad Manager, Aniview, Infy, or Triton DigitalVAST through the Media3 IMA extension, preloaded on a second player and swapped in when it loadsVAST through Google IMA 3.22.1VAST through Genuin's ad script, gen_ad.min.js 1.0.0
video_ad from PangleFull 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 orderNot supported; skipped
display_adGoogle Mobile Ads bannerGoogle Ad Manager bannerGoogle Ad Manager 300 × 250 banner; skipped in a slot smaller than 300 × 250
native_adGoogle Mobile Ads native adGoogle Ad Manager native ad; skipped in a container under 140 pointsRendered by the ad script
house_adThe house video keeps playing as a normal postThe house video plays as a normal postThe 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.5iOS 2.1.5Web 2.0.6
PlayerMedia3 with the IMA extensionGoogle IMA, breaks started as each is readyThe Genuin player with Google IMA, breaks scheduled by IMA
Skip buttonIMA's own, when the VAST creative is skippableNone; IMA's interface is turned offNone drawn by the Genuin player
SoundFollows the player's mute buttonFollows the viewer's mute setting, muted until they unmuteFollows the player's mute state
On an ad errorContent resumesContent resumesContent 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:

  1. The embed or placement details include sponsorship_id and cpm_rate.
  2. The SDK sends that id with every feed request for the embed or placement. On the web, the sponsorship_id option of init names the sponsorships the embed may ask for.
  3. 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

SituationWhat the viewer seesWhat to check
The embed or placement has no active presetContent only, no adsThe preset lists the embed or placement, and in-feed or in-stream ads are on for the platform
The brand has no house adThe slot is skipped and content moves upMark at least one post as a house ad
No programmatic source fillsThe house video, with no ad labelThe ad server configuration for the media type, and its traffic percentages
A Pangle or Google Mobile Ads source has no fillThe SDK moves to the next sourceThe ad unit ids in the ad server configuration
An in-stream break failsThe content video starts or resumesThe VMAP URL of the video provider
The preset is on, but the platform shows no adsContent onlyWith Custom settings, the tab for that platform. Mobile browsers use the Web tab.
Placement shows no adsContent onlyWhether the placement's style uses sections

Platform differences

Android 2.1.5iOS 2.1.5Web 2.0.6
Preset sub-object read on the deviceandroidios, or the whole objectNone
last_video_count countsPosts, ad slots, and Partnered Posts receivedPosts, ad slots, and Partnered Posts receivedEvery item received, including a start video the page opened with
In-stream ads when a video loopsRequested again only when the brand's in_video_stream ad setting is onRequested again only when the brand's in_video_stream ad setting is onRequested again on every loop
Ad Viewable Impression event2 seconds after the ad renders, while its container is visible2 seconds after the ad rendersNot 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.

See also

TRUST AND COMPLIANCE

© 2026 Genuin Inc.

Genuin Footer