My fill rate is low
What fill rate measures in Epom, why "Requests" can vanish from a report, and how to route a low fill rate to a concrete cause — no matching demand, a floor rejecting bids, or a missing passback.
Fill rate is the share of ad requests that came back with an ad. A low number means paid inventory is going to waste — the request arrived, but nothing served (or a blank / passback did). This page explains exactly what Epom counts, clears up two reporting traps that make fill rate look broken, and routes a genuinely low fill rate to the specific Epom lever that fixes it.
If the symptom is “this one placement never serves at all”, start with My ad is not serving instead — that is a wiring problem, not a fill-rate problem. Fill rate is for “requests come in, only some turn into impressions”.
What Epom actually measures
Several columns called “fill rate” live in different report types — don’t compare them across reports:
| Column | Report | Formula |
|---|---|---|
| Fill Rate | General report | impressions ÷ Requests, where Requests = impressions + requests that came back without an ad |
| Fill rate, % | Advanced report | eligible impressions ÷ direct requests |
| Effective fill rate, % | Advanced report | eligible impressions ÷ deliveries |
| Fill Rate | Header Bidding report | fills ÷ (fills + unfilled) — counted per header-bidding slot request, not per ad request |
- Fill Rate (General) is the plain-English number: of the ad requests received, how many produced a counted impression. Because the denominator already contains the impressions, it can never exceed 100%.
- Effective fill rate (Advanced) divides by deliveries (ad responses) instead of requests. It tells you a different thing: of the ads that were actually returned, how many became eligible impressions. A healthy Fill Rate with a low Effective fill rate points at impressions being rejected after serving (fraud / invalid), not at unfilled requests.
See Analytics metrics for every column’s exact derivation.
Trap 1 — Requests and Fill Rate disappear when grouped by advertiser or campaign
The single most common “my fill rate is broken” report is not broken — the column is simply gone because of how the report is grouped.
Corner case: Requests and Fill Rate vanish the moment a General report touches the demand side. Grouping by advertiser, campaign, banner (or their IDs), conversion action, attribution type, banner label, banner template, ISCI / Ad-ID or advertiser owner drops them; so does filtering on advertiser, campaign, banner, banner label, banner template or ISCI / Ad-ID, or splitting the columns by conversion action. An ad request happens before the ad server picks a demand entity, so a request cannot be attributed to one campaign or banner. With no Requests column, there is no denominator, so Fill Rate is hidden too. The columns also need the Analytics Report Column Requests and Impressions permissions.
Fix: group by supply-side dimensions only — placement, zone, site, country, date — when you want fill rate. Add the demand grouping in a separate report.
Trap 2 — you’re reading the wrong denominator
If Fill Rate reads far below what you expect, confirm you are on the General report’s Fill Rate, not the Advanced report’s Effective fill rate. They answer different questions: an Advanced eligible impression is a delivery minus the impressions a passback cancelled and the ones flagged invalid, so a low Effective fill rate beside a healthy Fill Rate is a passback-and-rejection story, not an unfilled-inventory story. Read the Valid passbacks and Rejected impressions columns (see the metrics reference) rather than going through the demand checks below.
Diagnose a genuinely low fill rate
Once you’re sure the column is real and it’s low, the cause is almost always one of four. Check them in order.
1. No matching demand for the request
The request arrived but no banner fit it — the most common real cause. Every stage of ad selection can empty the pool: nothing linked, a size/type mismatch, targeting too narrow, or everything capped or limited out.
- Run a General report grouped by placement with Requests and Impressions: high requests, near-zero impressions on a placement = that placement has requests it can’t fill.
- Then walk that placement through My ad is not serving — its checks (linking, size match, targeting, capping, limits) are the fill-rate causes, one per stage.
- A classic silent killer: country-targeted demand + unresolvable geo. When a visitor’s country can’t be resolved, include-country rules treat the request as a non-match and drop the banner — so those requests count but never fill. See the unknown-geo corner case in My ad is not serving.
2. A price floor is rejecting the demand you have
Floors filter out demand that pays too little — the request is fillable in principle, but every candidate is priced under the floor.
- Bid floor cards (banner / placement / site; managed with Bid Floor Management, an admin-only permission) drop DSP bids priced below the floor. They do not filter direct campaigns.
- Minimum margin (the Pricing card on a placement or site, with Manage Minimum Margin) is the setting that drops direct banners whose advertiser price does not clear the publisher payout by the margin you set. It skips CPC and CPA banners, and a banner with no price counts as a gross of zero. See What stops delivery, and what only changes the price.
- The site CPM threshold is a reporting figure and the last fallback for the DSP bid floor: when no more specific floor or price applies, DSP bids below it are rejected. It does not block direct campaigns.
- If the low fill rate is on RTB/DSP inventory, lower or remove the floor for that slice and re-measure; if it is on direct demand, look at minimum margin. A floor set higher than the market clears is unfilled inventory by design.
3. Programmatic demand simply didn’t bid
For inventory whose only demand is an OpenRTB DSP banner, an impression happens only when the partner bids and wins:
- No bid → the next banner in line serves, or the passback; the request still counts as a request, so unbid RTB requests directly depress fill rate.
- The partner’s own pre-targeting (blocked lists, geo, device) can filter the request before a bid is even made.
- On networks running creative scanning, a blocked creative is dropped from the auction and the runner-up wins — ask your network administrator to check the creative’s scan verdict (Admin → Demand partners (DSP) → DSP creative scan, or Account → RTB → DSP creative scan for a role that holds DSP Creative Scan) if a specific DSP creative never delivers.
DSP partners analytics (Admin → Demand partners (DSP), or Account → RTB for a role that holds DSP Partners Analytics) shows Requests, Bids and Wins per partner, which tells you whether the gap is “no bid” or “bid lost”.
4. Unfilled requests are returning blanks instead of a fallback
A low fill rate is only lost revenue if the unfilled requests return nothing. Turning empties into a fallback doesn’t raise the fill-rate number, but it stops the waste:
- Set the placement’s Default code (Advanced settings; it needs the Placement Default Code permission) so an unfilled request hands off to another ad source instead of rendering blank.
- Use daisy chaining to stack several demand sources so a request that one entry can’t fill falls through to the next before giving up.
- A campaign on the lowest priority tier, House ads, gives the request something to serve when everything above comes up empty — it still has to pass targeting, caps and limits.
Note: a request answered by the placement’s Default code is not an impression — the response carries a no-impression beacon, so the request stays in Requests as unfilled. Heavy Default code use therefore lowers Epom-side Fill Rate while still monetizing the request elsewhere. Read fill rate alongside your passback strategy, not in isolation.
Corner cases
Corner case: the General Fill Rate roll-up (summary) row recomputes from summed impressions ÷ summed requests — it is not the average of the per-row fill rates. A few huge-volume placements dominate the network number; drill into per-placement rows to find the ones actually starving.
Corner case: General Fill Rate cannot go above 100% — Requests already includes the impressions. The Advanced Fill rate, % divides eligible impressions by direct requests, two separate counts that are not tied together the same way, so do not expect it to track the General figure row for row.
When you escalate
If the checks don’t explain it, contact your network administrator with the placement / site IDs, the report type and grouping you used, the time window and time zone, and the two numbers (requests vs impressions) you’re comparing. Network administrators can additionally check gates account users can’t see — consent enforcement, bot filtering and, if turned on, IP bans — that suppress requests before any banner is considered.
Related
- Analytics metrics — every fill-rate column’s exact formula
- My ad is not serving — the per-stage causes behind unfilled requests
- Set a site CPM threshold — the RTB floor that rejects cheap bids
- Daisy chaining and passbacks — catch unfilled requests
- Run a pre-roll waterfall across several video networks — fill per network for VAST setups
- Analytics discrepancies — “No ads” and fill per advertiser
- Glossary