Troubleshooting Guide
Work through this guide before contacting support. Start by raising the log level — most problems announce themselves.
TeadsLog.level = LogLevel.debug;
Quick Checklist
-
TeadsSdk.configure()called once at app start, and it did not throw -
articleUrlprovided on every placement - The widget ID matches the placement type
- Nothing overlays the placement — not even a transparent widget
- Android: Teads Maven repository added, AdMob
APPLICATION_IDpresent, NDK pinned - iOS:
platform :ios, '15.0',pod installrun,NSUserTrackingUsageDescriptionpresent - Tested on a real device, not only a simulator or emulator
Installation Issues
Android: Could not resolve tv.teads.sdk.android:sdk
The Teads Maven repository is missing, or your build blocks project-level repositories.
// android/build.gradle
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://teads.jfrog.io/artifactory/SDKAndroid-maven-prod" }
}
}
If android/settings.gradle sets
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS), the repository must go
in settings.gradle's dependencyResolutionManagement block instead.
Then:
cd android && ./gradlew clean && cd ..
flutter clean && flutter pub get
Android: the app crashes at launch, before any Dart runs
The AdMob application ID is missing. The native SDK's transitive play-services-ads
dependency has a content provider that crashes at process start without one.
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY" />
This is required even if you do not use AdMob. See Installation.
Android: NDK errors or a version-mismatch warning
Pin the NDK explicitly in android/app/build.gradle:
android {
ndkVersion = "27.1.12297006" // or newer
}
Android: Unsupported class file major version, or other JDK errors
Use JDK 17 or 21. Android Studio's bundled JBR normally works with no setup. Otherwise:
export JAVA_HOME=/path/to/jdk21
Prefer JAVA_HOME or ~/.gradle/gradle.properties over committing
org.gradle.java.home to your repository — a hardcoded JDK path breaks the build on
every other machine and on CI.
Android: minSdkVersion conflict
The plugin requires minSdk 24. Raise your app's value; do not override the plugin's.
iOS: pod install cannot find TeadsSDK
sudo gem install cocoapods
rm -rf ios/Pods ios/Podfile.lock
cd ios && pod install
If it persists, clear the CocoaPods cache: pod cache clean --all.
iOS: missing-framework errors in Xcode
Open ios/Runner.xcworkspace, not ios/Runner.xcodeproj. Then Product → Clean Build
Folder, and if needed rm -rf ~/Library/Developer/Xcode/DerivedData.
iOS: deployment-target errors
platform :ios, '15.0' in the Podfile, and the Runner target's
IPHONEOS_DEPLOYMENT_TARGET at 15.0 or higher. Also raise any post_install hook
that pins IPHONEOS_DEPLOYMENT_TARGET — a hook left behind at 14.0 puts the pods
below the app linking them, which surfaces as a compatibility warning from
CocoaPods rather than a build failure.
No Ad Appears
Work down this list in order.
1. Did configure succeed?
try {
await TeadsSdk.configure('YOUR_APP_KEY');
} catch (e) {
debugPrint('Teads configure failed: $e');
}
2. Does the widget ID match the placement?
Pointing Banner or Interstitial at Feed's MB_1 serves a feed, which looks exactly
like a broken placement. This is the single most common false bug report.
Use MB_10 for Banner, INT_MW_1 for Interstitial, MB_1 for Feed.
3. Is the Feed's widgetIndex non-zero?
A Feed placement with widgetIndex: 1 (or higher) never loads unless a
widgetIndex: 0 placement loads on the same page. No error is reported — it simply
waits forever.
Set widgetIndex: 0 unless you deliberately coordinate multiple Feeds.
4. Is it a no-fill?
No-fill is a normal outcome, not a bug. Check onFailed:
onFailed: (error) => debugPrint('No ad: ${error.reason}'),
5. Is the placement actually laid out?
- Not inside a zero-height or zero-width parent
- Not inside a collapsed
VisibilityorOffstage - Not clipped by a fixed-size
SizedBoxsmaller than the creative
6. Android emulator only: is DNS resolving?
The emulator's default DNS resolver frequently fails on
widgets.outbrainimg.com with ERR_NAME_NOT_RESOLVED, which looks exactly like a
broken Feed. The host machine resolves it fine — the failure is inside the emulator.
Boot the emulator with explicit DNS servers:
emulator -avd <name> -dns-server 8.8.8.8,8.8.4.4
Real devices are not expected to hit this.
Ad Appears But Behaves Wrongly
Clicks do nothing
- Look for an overlay over the placement — including a transparent
Container, a gradient scrim, or aStacksibling drawn on top - Look for an ancestor
IgnorePointerorAbsorbPointer - Test on a real device; touch handling in emulators is less reliable
The browser opens twice on click
You are opening click.url from onClicked. The SDK already does. Use the callback for
analytics only.
The one exception is FeedPlacement.onOrganicClick, which exists so you can navigate.
The placement does not resize
The widgets resize themselves as the creative reports its height. If yours does not:
- Remove any fixed-height wrapper
- Make sure the placement is in a scrollable or flexible parent
- Check
onEventforTeadsAdEvent.heightUpdated
Feed fullscreen video breaks the layout
Collapse siblings with Visibility(maintainState: true) or a zero height. Removing a
sibling re-parents the WebView and it stops painting entirely.
Also fold your own chrome away in onFullScreenChange — hide the app bar, stop the
surrounding scroll view moving, and hide the system bars.
Feed renders as a large black area
Rare, and specific to Android's texture-layer rendering path at very large content heights. The plugin hosts Feed's WebView as a real Android view by default precisely to avoid this, so you should not see it unless that default has been overridden.
Rotation is not reflected in a Banner (iOS)
You have not forwarded viewWillTransition. Android needs nothing; UIKit only hands the
transition coordinator to a real view controller:
override func viewWillTransition(
to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator
) {
super.viewWillTransition(to: size, with: coordinator)
TeadsFlutterPlugin.forwardViewWillTransition(to: size, with: coordinator)
}
Two Banners conflict
BannerPlacement at a timeA process-wide flag in the native SDK means the last wrapped Banner or Feed placement
created wins. Keep to one live BannerPlacement.
Interstitial Issues
show() returns false
There was no ad to show. Either load() has not completed, or the ad expired.
await interstitial.load();
// Wait for onReady, then:
if (await interstitial.isReady) {
await interstitial.show();
}
The ad was ready and now is not
Ads expire on a native TTL — roughly an hour by default. Never cache isReady;
re-check it immediately before show().
Memory grows across screens
You are not disposing. InterstitialPlacement holds a native WebView and an Open
Measurement session:
void dispose() {
_interstitial?.dispose();
super.dispose();
}
Recommendations Issues
fetch returns an empty list
- Confirm the widget ID is a recommendations ID (
SDK_1,RECS_1,TEST_RECS), not a Feed one - Confirm the
articleUrlis reachable - An empty result is a valid response, not necessarily a fault
No viewable impressions, so no revenue
You must drive RecommendationsViewabilityReporter yourself — the SDK cannot see a list
it did not render. See Recommendations Viewability.
The most common cause is creating a new GlobalKey on every build, which restarts
measurement each frame so nothing ever reaches the threshold. Cache the keys.
A click is reported for an item nobody tapped
You are calling registerClick too early. It reports the click as well as resolving
the URL, so calling it after fetch to pre-compute URLs reports a phantom click for
every organic item.
Call it only in your onTap.
Privacy Issues
The ATT prompt never appears
NSUserTrackingUsageDescriptionmust be inInfo.plist— without it iOS denies the request instead of prompting- Request it after the first frame, not before
runApp - iOS only asks once per install. Reinstall the app to test again
The app hangs on a white screen at launch (physical iPhone)
You are awaiting requestTrackingAuthorization() before runApp. The completion handler
never fires while there is no UI on screen. The Simulator does not reproduce this. Move
the call into your first screen's post-frame callback.
Ads request without consent applied
Show your CMP before creating placements. Privacy signals are read when a placement assembles its request.
If you set TeadsPrivacy overrides, they win over your CMP's stored values until you
call clearAllOverrides().
Testing & Debugging
Raise the log level
TeadsLog.level = LogLevel.debug;
Lines are tagged by component — Feed, Banner, Interstitial, Recommendations,
RecommendationsViewability. See Logging.
Native logs
The wrapped placements (Media, Banner, Interstitial) also log natively:
# Android
adb logcat | grep -i teads
On iOS, filter the Xcode console for Teads.
Inspect network traffic
Use a proxy such as Charles or Proxyman. Note that all SDK network calls go through the platform HTTP stacks, so they honour the OS proxy settings and are visible.
Widget tests
Placements that use platform views cannot render in flutter test. Use the test doubles:
import 'package:teads_flutter/teads_flutter_mocks.dart';
TeadsSdk.instance = MockTeadsSdk();
TeadsPrivacy.instance = MockTeadsPrivacy();
Recommendations.instance = MockRecommendations(recommendations: [...]);
This is a separate import from the main library on purpose, so test scaffolding never ships in production code.
Always test on real devices
Emulators and simulators misrepresent DNS, touch handling, video playback and rendering performance. Everything in this guide assumes a real-device check before you conclude anything.
Known Limitations
Stated plainly so you can judge what matters for your app:
- One live
BannerPlacementat a time. A process-wide flag in the native SDK means the last wrapped Banner or Feed placement created wins. - Media Native is not implemented.
- Feed's dark mode is the only config field that applies to a loaded placement. Every other field takes effect when the page is recreated.
- Recommendations viewability measurement is not a general occlusion check — see its limitations.
- Feed autoplays muted video on iOS. Deliberate: a muted video plays on its own, while anything with sound still requires a user action.
Getting Help
If nothing above applies:
- Re-check the Prerequisites checklist
- Confirm you are on the latest version available to you
- Reproduce in a minimal app, so plugin interactions are ruled out
- Contact support with logs, versions and reproduction steps
Quick Reference
Installation checklist
- Dependency added,
flutter pub getrun - Android: Teads Maven repository
- Android: AdMob
APPLICATION_ID - Android: NDK pinned,
minSdk24+ - iOS:
platform :ios, '15.0',pod install - iOS:
NSUserTrackingUsageDescription - Both platforms build
Integration checklist
-
TeadsSdk.configure()once at start - ATT requested after the first frame (iOS)
-
articleUrlon every placement - Correct widget ID per placement
-
onFailedwired up;onUnsupportedwired up for Feed -
InterstitialPlacement.dispose()called -
RecommendationsViewabilityReporter.dispose()called - Tested on real iOS and Android devices
Pro tip: for a placement that shows nothing, check the widget ID and the Feed
widgetIndex first. Between them they explain most "no ad" reports.