Appearance
Targeting
Any placement rule can be restricted by where the visitor is, what they're looking at, and when they're looking. The same keys also work on the [vas_ad] shortcode, so you can target an ad placed anywhere.
All targeting is evaluated server-side. A visitor who doesn't match never receives the ad markup at all, so AdRotate counts no impression and your advertiser isn't charged for an impression that was never eligible.
Dimensions combine with AND — a rule with both geo= and terms= must satisfy both. Values within one dimension are OR-matched and separated by semicolons, because commas already separate rule keys.
Geographic — geo=
| You want | Write |
|---|---|
| Everywhere | geo=all, or omit it |
| Countries | geo=US;GB;RO, or names — geo=USA;UK;Germany |
| Regions / states | geo=region:California;state:Texas (name or code) |
| Cities | geo=city:London;city:Paris |
| Country or region | geo=US;region:Bavaria |
Every region needs its own prefix
Write geo=region:Virginia;region:Bavaria — not region:Virginia;Bavaria. The second value, having no prefix, is read as a country, and since "Bavaria" isn't a country it's dropped.
Detection providers
Set one under Settings → Voxel Ads → Geo targeting.
| Provider | Levels | Notes |
|---|---|---|
| CloudFlare header | Country | Instant, free, no API call. Needs the site behind CloudFlare. |
| ip-api.com | Country, region, city | Free, no key, 45 requests/minute. |
| ipinfo.io | Country, region, city | Free tier; token recommended. |
| Custom | Whatever you return | Via the voxel_adrotate_sync/geo_lookup filter. |
Region and city targeting need ip-api or ipinfo — the free CloudFlare header carries only the country.
City accuracy is approximate
IP-to-city resolution is right maybe 50–75% of the time; mobile carriers, VPNs and ISP routing often resolve to a nearby or larger city. Treat city: as soft targeting and sell it accordingly. Country and region are the reliable levels.
Lookups are cached per visitor IP for a configurable number of hours. Settings → Voxel Ads → Maintenance has a Test IP lookup tool and a Flush geo cache button.
When location is unknown
When location is unknown decides what happens if a needed dimension can't be resolved:
- Show — the ad runs. Maximises delivery; some ads reach the wrong place.
- Hide — the ad is withheld. Guarantees accuracy; loses some impressions.
Choose based on what you promised the advertiser. A rule that matches on one dimension is never affected — this only applies when the answer is genuinely unknown.
Category — terms=
Restrict a rule to pages carrying one of the listed taxonomy term slugs, from any taxonomy:
shortcode=[adrotate group="2"], interval=4, terms=restaurants;barsTerm context comes from the listing's own terms on a single post, or the queried term on a taxonomy archive. No term context means no match, so a targeted ad stays hidden rather than leaking somewhere irrelevant.
This is most useful with single-post injection.
Time of day — days= and hours=
shortcode=[adrotate banner="19"], position=3, days=sat;sun
shortcode=[adrotate group="2"], interval=4, hours=11-14;18-22
shortcode=[adrotate banner="19"], position=2, hours=22-2days=takesmontosun, in site time.hours=takes 24-hour ranges. Start inclusive, end exclusive —11-14means 11:00 to 13:59. A bare hour likehours=15means that hour only.- Ranges wrap past midnight:
22-2covers 22:00 to 01:59.
A restaurant can buy lunch and dinner hours only:
shortcode=[adrotate group="2"], interval=5, geo=US, terms=restaurants, hours=11-14;18-22Dayparting and full-page caching
Dayparting is evaluated per request. If you run full-page caching, a page cached at 10:00 keeps serving its 10:00 ads until it expires. Keep the cache TTL shorter than your hour granularity, or exclude dayparted pages from the cache.
The [vas_ad] shortcode
To target an ad placed outside a feed — in page content, an Elementor Shortcode widget, or a template — wrap it:
[vas_ad geo="US;region:California"][adrotate banner="19"][/vas_ad]
[vas_ad terms="restaurants;bars"][adrotate group="2"][/vas_ad]
[vas_ad days="fri;sat" hours="22-2"][adrotate banner="19"][/vas_ad]Everything at once, plus the consent gate:
[vas_ad geo="US;region:California" terms="restaurants" days="fri;sat;sun" hours="11-23" consent="yes"][adrotate group="2"][/vas_ad]Non-matching visitors get nothing — the inner shortcode never runs, so no impression is counted.
GDPR consent
Under Settings → Voxel Ads → Privacy & consent, injection can be withheld until a consent cookie is present. Until the visitor consents, AdRotate renders nothing and sets no tracking cookie.
| Setting | Meaning |
|---|---|
| Require consent | Master switch. |
| Consent cookie | The cookie name your consent banner sets. |
| Accepted values | Comma-separated values that count as consent. Blank means any non-empty value. |
Common cookie names: cookie_notice_accepted (Cookie Notice), Complianz and CookieYes set their own — check your banner's documentation.
Add consent="yes" to a [vas_ad] to gate an individual placement. For a consent-management platform that decides server-side, use the voxel_adrotate_sync/has_consent filter — see Developer Reference.

