---
title: Common reasons ads do not show
description: Diagnose no-fill, consent, configuration, device, and network problems using v17 outcomes.
---

Start with an official `TestIds.*` unit on a development build. If that works, register the device
before trying your own unit. Record the v17 `status`, `error.reason`, `error.phase`, and
`responseInfo` before changing configuration.

<Warning>
  Do not repeatedly request or click production ads while diagnosing. Use official test units or a
  registered test device as described in [Testing ads](/testing).
</Warning>

## Symptom → likely cause → fix

| Symptom                                                                     | Likely cause                                                                                             | Fix                                                                                                                                                                                                                                                            |
| --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| An official test unit works, but your production unit does not              | The device is not in test mode, the unit is new or inactive, or live inventory is unavailable            | Register the device before using your unit, verify the unit's format and status in AdMob, and inspect `reason` plus `responseInfo`. Never click an unlabeled live ad.                                                                                          |
| A Google demo unit does not load and app-ads.txt looks suspicious           | The test request has a device, network, App ID, format, or SDK problem—not a missing demo publisher line | Do **not** add Google's demo publisher to your app-ads.txt. Demo units are not associated with your account and Google describes them as configured to return test ads. Verify the App ID, ad format, network, and device image.                               |
| `canRequestAds === false`                                                   | UMP has not established request eligibility for the current session                                      | Call `AdsConsent.requestInfoUpdate()`, present a required form, and initialize/load only after `canRequestAds` is true. Test debug paths both inside and outside the EEA.                                                                                      |
| Consent UI appears after ads already request                                | The SDK or a hook initialized/preloaded before consent was resolved                                      | Gather consent and set request configuration before `mobileAds().initialize()`. Keep hook `autoLoad` false until eligible.                                                                                                                                     |
| A new app or ad unit shows no live impressions                              | Account/app readiness review or unit propagation is incomplete                                           | Google says new units typically take up to an hour and, uncommonly, a few days. Check account, app, and Policy Center status rather than issuing rapid retries.                                                                                                |
| An unpublished iOS app does not serve live ads                              | The app is not listed and linked for AdMob readiness review                                              | Use test ads during development. List the app in the Apple App Store, link the listing in AdMob, and wait for readiness approval before expecting full live serving.                                                                                           |
| The app crashes or every request fails immediately after startup            | The AdMob **App ID** is missing, malformed, or configured for the wrong platform                         | Verify Expo plugin or bare configuration. An App ID contains `~`; an ad unit ID contains `/`. Neither is the Android `applicationId` package name. Rebuild after changing native configuration.                                                                |
| Fullscreen hook reports `status === 'no-fill'` and `error.phase === 'load'` | The request completed but no matching inventory or mediation source filled                               | Treat `reason: 'no-fill'` or `'mediation-no-fill'` as an inventory outcome. Use backoff, inspect waterfall rows, and do not convert it into an immediate retry loop.                                                                                           |
| Hook reports `status === 'error'` with `error.phase === 'show'`             | A loaded ad could not be presented, was reused, or lost a valid presentation context                     | Fix the lifecycle/presentation problem. Do not classify a show-phase failure as routine no-fill, even if a native message mentions inventory.                                                                                                                  |
| Native fails on Android while banner or interstitial test ads load          | The AVD uses a Google APIs image without the Play Store or has stale Play services                       | Recreate it with a Google Play (`google_apis_playstore`) image, preferably API 26+, and update Play services. This Native-specific signature is observed in this repository's integration environment, not promised by Google for every image/SDK combination. |
| Test ads work but live requests vary by location or time                    | Demand, targeting, frequency caps, floors, or regional inventory differ                                  | Inspect Ad Inspector and `ResponseInfo`, test on a real device/network, and treat isolated no-fill as expected inventory behavior.                                                                                                                             |
| A GAM sample unit occasionally returns no fill                              | The request did not receive a matching test creative, or the device/network path is unhealthy            | Confirm the matching `TestIds.GAM_*` format, retry later with backoff, and use Ad Inspector. A no-fill result alone does not prove the React Native integration is broken.                                                                                     |
| Requests fail only on one wireless network                                  | Private DNS, VPN, firewall, or content filtering blocks ad hosts                                         | Temporarily switch Private DNS to Automatic and disable filtering/VPN for a controlled test. Restore security settings afterward and permit required hosts instead of shipping a bypass.                                                                       |

Google's [ads-not-showing guide](https://support.google.com/admob/answer/9469204) documents
account approval, new-unit activation, and iOS listing constraints. Its
[onboarding troubleshooting](https://support.google.com/admob/answer/9905175) also covers format
mismatches, floors, and missing publisher data.

## Read v17 diagnostics first

For fullscreen hooks:

```ts
import { useEffect } from 'react';
import { TestIds, useInterstitialAd } from 'react-native-google-mobile-ads';

export function useDiagnosedInterstitial() {
  const ad = useInterstitialAd({
    adUnitId: TestIds.INTERSTITIAL,
  });

  useEffect(() => {
    if (ad.status === 'no-fill') {
      console.info('No fill', ad.error?.reason, ad.responseInfo?.responseId);
    } else if (ad.status === 'error') {
      console.error('Ad failed', ad.error?.phase, ad.error?.reason, ad.error?.responseInfo);
    }
  }, [ad.status, ad.error, ad.responseInfo]);

  return ad;
}
```

`responseInfo.adapterResponses` shows waterfall latency and per-adapter outcomes. A response ID can
help support teams find a request. See
[Revenue telemetry and auction diagnostics](/revenue-telemetry-and-auction-diagnostics).

<Info>
  Legacy integer codes can help when comparing a native Google SDK log, but application logic should
  branch on v17 `status`, `reason`, and `phase`. Those fields distinguish normal load-time no-fill
  from configuration, transport, mediation, and show failures.
</Info>

## Verify identifiers without conflating them

- **Android application ID / iOS bundle ID:** your store package identity.
- **AdMob App ID:** app-level native configuration, in the form `ca-app-pub-…~…`.
- **Ad unit ID:** one placement and format, in the form `ca-app-pub-…/…` or a GAM path.
- **Hashed test device ID:** a device identifier emitted by the SDK for test registration.

Changing an Android application ID or iOS bundle ID changes the store identity; it is not a fix for
an invalid AdMob App ID. Follow [Configuration](/configuration) and rebuild when App ID
configuration changes.

## Device and consent checks

- Use a Google Play system image for Android Native testing and a real device for final UMP/ATT
  smoke testing.
- Keep Google Play services current. The SDK can access Advertising ID when available, but that ID
  is not interchangeable with the hashed test-device identifier generated by the SDK.
- Reset UMP only in test builds, then request fresh consent information. ATT reset requires
  reinstalling the iOS app.
- Confirm the app is allowed to request ads before initialization and loading.

See [Testing ads](/testing) for the complete checklist and
[Ad Inspector and the debug menu](/ad-inspector) for request-level inspection.

## `googleMobileAds/timeout` on load

A load that fails with `googleMobileAds/timeout` (structured `reason: 'timeout'`) is the library mapping Google Mobile Ads iOS `GADErrorTimeout` (native error code `5`) from the SDK completion handler. The React Native bridge does **not** invent or extend a request timer on interstitial, rewarded, rewarded interstitial, app open, or banner load paths — it forwards that iOS SDK `NSError`. Android error mappers have no timeout arm for this code (an equivalent native code would surface as `unknown`, not `googleMobileAds/timeout`).

When every format fails at a fixed ~ten seconds after `initialize()` while the same session can `fetch` ad hosts successfully:

1. Confirm `initialize()` resolved and consent / `canRequestAds` allow requests.
2. Treat app-level URL fetch success as **not** proof the SDK auction path works; the Mobile Ads SDK uses its own request machinery.
3. Do not look for a package “request timeout” knob — none exists (pinned SDK request configuration has no request-timeout API).
4. Capture Mobile Ads SDK logs, try a second physical device, and escalate to Google with the Google Mobile Ads SDK version plus device/OS when Google **test** unit IDs fail this way after a successful initialize.

New Architecture vs Paper does not change this mapping: both call the same native `loadWithAdUnitID` / load APIs and pass through the completion error.

## Extra links

- Mobile Ads SDK [iOS](https://developers.google.com/admob/ios/quick-start), [Android](https://developers.google.com/admob/android/quick-start)
- [Common reasons for ads not showing](https://support.google.com/admob/answer/9469204)
- [Migrating to v17](/migrating-to-v17) — structured errors, no-fill vs failure, diagnostics
- [Revenue telemetry and auction diagnostics](/revenue-telemetry-and-auction-diagnostics) — `ResponseInfo` after load
