diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adapex/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adapex/article.mdx
index 49221383..b98f6b76 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adapex/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adapex/article.mdx
@@ -1,15 +1,25 @@
## Who is Adapex a fit for?
-Adapex suits a publisher who already sells ads through Google and wants a team to manage the setup. You keep your own Google Ad Manager account, so you aren't starting from zero.
+A publisher who already sells ads through Google and wants a team to run the setup. If you use AdSense, Ad Exchange, or Prebid today, Adapex can take that over, and you keep your own Google Ad Manager account.
+
+If you're just starting out, [Google AdSense](/ad-networks/google-adsense) has no traffic minimum and you can set it up yourself.
+
+## What does onboarding through MCM mean?
+
+MCM is Google's way of letting a partner manage ads for another publisher. Your Ad Manager account stays yours, and Adapex works with it under that link.
## Can you try Adapex without a long contract?
Yes. Adapex says no long-term contract is needed. It offers better terms on longer contracts, so ask what you'd give up by staying short.
-## What does onboarding through MCM mean?
+## How long will you wait for your money?
-MCM is Google's way of letting a partner manage ads for another publisher. Your Ad Manager account stays yours, and Adapex works with it under that link.
+About two months. On Net 60, each month's earnings arrive 60 days after the month ends. [Raptive](/ad-networks/raptive) pays on Net 45 and [Media.net](/ad-networks/media-net) on Net 30, so plan for a longer gap if you switch from a faster payer.
+
+## What should you ask Adapex before you sign?
+
+Ask for your share, the payment minimum, and whether Adapex must be your only ad partner. None of these are public. If you're offered a longer contract, get the better share or features it adds in writing.
## How can you check if a site uses Adapex?
-Look for Adapex in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Adapex.
+Look for Adapex in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adapex/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adapex/joining.mdx
index d8cd9d5b..499da185 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adapex/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adapex/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Adapex?
-
Adapex doesn't publish a traffic minimum, site rules, or the regions it accepts. You apply through the contact form on its site.
If you already run AdSense, Ad Exchange, or Prebid, Adapex can bring that setup in. Onboarding goes through Google Ad Manager's Multiple Customer Management (MCM).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/aditude/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/aditude/article.mdx
index 85aa78c8..8f9332b7 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/aditude/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/aditude/article.mdx
@@ -1,11 +1,21 @@
## Who is Aditude for?
-Aditude works with web and app publishers on their ad technology. It doesn't say who qualifies, so the only way to know is to ask.
+Aditude works with web and app publishers on their ad technology. It doesn't say who qualifies, so the only way to know is to ask its team.
## What should you ask Aditude before you sign?
-Ask for the share you'd get, when you'd be paid, and whether Aditude must be your only ad partner. Ask how much notice you'd need to leave. None of this is on its public pages, so get it in writing.
+Aditude publishes no publisher terms, so get these answers in writing:
+
+1. What share of ad revenue do you keep?
+2. When are you paid, and what's the minimum?
+3. Must Aditude be your only ad partner?
+4. Who decides where ads go on your pages?
+5. How much notice do you need to give to leave?
+
+## What if you want public terms before you talk to anyone?
+
+Pick a network that publishes its rules. [Google AdSense](/ad-networks/google-adsense) has no traffic minimum. [Raptive](/ad-networks/raptive) and [Mediavine](/ad-networks/mediavine) publish their share and pay day. [Ezoic](/ad-networks/ezoic) publishes its share in its terms.
## How can you check if a site uses Aditude?
-Look for Aditude in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Aditude.
+Look for Aditude in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/aditude/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/aditude/joining.mdx
index 01f46e54..cf25c6e0 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/aditude/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/aditude/joining.mdx
@@ -1,3 +1 @@
-## Who can join Aditude?
-
-Not public. Aditude doesn't publish a traffic minimum, site rules, accepted regions, or how to apply. Contact its team to ask whether your site fits.
+Aditude doesn't publish a traffic minimum, site rules, accepted regions, or how to apply. Contact its team to ask whether your site fits.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/article.mdx
index b259d509..ec83e790 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/article.mdx
@@ -1,15 +1,27 @@
+## Who is Adnimation a fit for?
+
+Sites with steady traffic that want display, video, and native ads run for them. Adnimation asks for substantial traffic but doesn't give a number, so contact its team if you're unsure.
+
+It's not a fit for gambling, porn, or drug sites. Those are restricted.
+
## Is Adnimation a fit for a small site?
-Probably not the managed service, since it asks for substantial traffic. Adnimation's MAP product has no pageview minimum, but it's a separate program with its own terms.
+Probably not the managed service. Adnimation's MAP product has no pageview minimum, but it's a separate program with its own terms. Don't assume the managed service's pay terms apply to MAP.
+
+For a small site, [Google AdSense](/ad-networks/google-adsense) has no traffic minimum, and [Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month.
+
+## How fast does Adnimation pay?
+
+Faster than many managed services. Net 35 means each month's money arrives about five weeks after it ends. Many networks on this list pay on Net 60, such as [Monumetric](/ad-networks/monumetric) and [Playwire](/ad-networks/playwire).
## Can you leave Adnimation?
Yes. There's no lock-in contract, but you need to give notice. Ask how much before you sign, since it isn't public.
-## What ads will Adnimation run on your site?
+## How quickly will you get help?
-Display, video, and native or recommendation ads, with header bidding behind them. You can ask to change where they sit on your pages.
+Adnimation says it replies in under two hours on average. You can reach it by email, phone, WhatsApp, Telegram, or Skype, which helps if something breaks on a busy day.
## How can you check if a site uses Adnimation?
-Look for Adnimation in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Adnimation.
+Look for Adnimation in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/joining.mdx
index 50cdcf62..394d0250 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adnimation/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Adnimation?
-
Adnimation asks for substantial traffic but doesn't publish a number. It reviews each site, and you apply by contacting its team. It doesn't say which regions it accepts.
Sites with gambling, porn, or drug content are restricted.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/article.mdx
index f94fbfdc..bf7a48a8 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/article.mdx
@@ -1,11 +1,23 @@
## Who is AdPushup for?
-Publishers who want help managing ad placements and price floors. AdPushup doesn't publish who qualifies, so submit your site and see what its review says.
+Publishers who want help managing ad placements and price floors, with real-time reports. AdPushup says it has no pageview minimum, but it looks for about $3,000 a month in ad revenue. Submit your site and see what its review says.
## Are AdPushup's public terms current?
-Maybe not. The public terms are several years old and may not match today's agreements. Read the agreement you're offered, and go by that.
+The terms AdPushup links to were last revised in April 2021. They don't set your share. That comes from a separate Publisher Agreement, so read the one you're offered and go by that.
+
+## What share do you keep?
+
+It's set in your Publisher Agreement, not in the public terms. Ask AdPushup to show the rate in writing, along with the $50 minimum and Net 45 timing, before you sign.
+
+## What could get your AdPushup account in trouble?
+
+Invalid traffic. The terms ban it along with illegal, adult, hateful, fraudulent, and infringing content. If you buy traffic or run click schemes, expect problems with AdPushup and with most other networks.
+
+## What should you ask before you sign?
+
+Ask whether AdPushup must be your only ad partner and how much notice you need to leave. Neither is in its current public pages.
## How can you check if a site uses AdPushup?
-Look for AdPushup in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to AdPushup.
+Look for AdPushup in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/joining.mdx
index e7c6701d..39361efe 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join AdPushup?
+AdPushup looks at your ad revenue, not your pageviews. It doesn't publish accepted regions or how long review takes. You submit your site on its onboarding page, and its team approves or rejects it.
-AdPushup doesn't publish a traffic minimum, accepted regions, or content rules. You submit your site on its onboarding page, and its team reviews it.
+Its terms ban illegal, adult, hateful, fraudulent, and infringing content, plus invalid traffic. Once approved, you install AdPushup's code on your site.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/pay.mdx
index 058d2be4..c357ec3a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/pay.mdx
@@ -1,5 +1,5 @@
## How does AdPushup pay?
-The public numbers come from AdPushup's older terms, revised in 2018. They set a default 20% service fee, so you keep 80%, with a $50 minimum and payment on Net 45. Your current agreement may differ, and that agreement is what counts.
+AdPushup's public terms, last revised in April 2021, set the minimum and timing. They leave your share to a separate Publisher Agreement, so the rate you get is the one written there.
-Payment methods and currency are not public.
+You can be paid by direct deposit, wire transfer, or PayPal. The currency is not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/rules.mdx
index 3247d813..32a07d22 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/adpushup/rules.mdx
@@ -1,3 +1,3 @@
## What rules does AdPushup set?
-The older terms ban invalid traffic and other policy breaks. Current rules on exclusivity, ad placement, content, contract length, and notice are not public.
+The terms ban invalid traffic and illegal, adult, hateful, fraudulent, and infringing content. Rules on exclusivity, ad placement, contract length, and notice are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/article.mdx
index f6302c9c..b748b97c 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/article.mdx
@@ -1,15 +1,25 @@
-## Can you run APS with another ad network?
+## Who is APS a fit for?
+
+Web publishers who already run Google Ad Manager and represent their own sites. UAM, its Unified Ad Marketplace, is built for them. APS says it works with publishers worldwide.
-Yes, for UAM. It's built to run next to your other header bidding partners, so you don't have to drop them.
+It's not a starting point for a new site. UAM is invitation only, with no public form. If you don't use Ad Manager yet, start with [Google AdSense](/ad-networks/google-adsense) or a managed network.
## How do you get access to APS?
-Contact APS and ask. UAM is invitation only, and there's no public form. It suits sites that already use Google Ad Manager.
+Contact APS and ask. There's no public application or traffic rule, so have your Ad Manager setup and current header bidding partners ready to describe.
+
+## Can you run APS with another ad network?
+
+Yes, for UAM. It's built to run next to your other header bidding partners, and its code can sit outside your wrapper. You don't have to drop anyone.
## What does the UAM fee mean for you?
-APS takes its fee out of each bid before the auction runs. So the bids that compete for your ad space are already net of it.
+APS takes 10% out of each bid before the auction runs. So the bids that compete for your ad space are already net of it. Compare final earnings, not bid prices, when you test it.
+
+## When does APS pay?
+
+Once a month, on Net 60, with a $5 minimum. The low minimum means even small UAM earnings get paid out.
## How can you check if a site uses Amazon Publisher Services?
-Look for Amazon Publisher Services in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Amazon Publisher Services.
+Look for Amazon Publisher Services in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/joining.mdx
index 11f639a0..885afda5 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/amazon-publisher-services/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Amazon Publisher Services?
-
The Unified Ad Marketplace (UAM) is invitation only. It's for web publishers who represent their own sites directly and use Google Ad Manager. APS says it works with publishers worldwide.
There's no public traffic minimum or application form. Contact APS to ask for access. These rules are for UAM, not every APS product.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/article.mdx
index 55fe6cec..ab84566b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/article.mdx
@@ -1,11 +1,22 @@
## Who is AnyManager for?
-Web and app publishers who want header bidding and pricing handled in one platform. AnyMind doesn't publish who qualifies, so contact its team.
+Web and app publishers who want header bidding, price tuning, and analytics in one platform. AnyMind doesn't publish who qualifies, so contact its team.
## How does AnyMind set your share?
-You agree on a fixed share before you start. Ask for it in writing, since AnyMind doesn't publish it.
+You agree on a fixed share before you start. AnyMind doesn't publish it, so ask for it in writing.
+
+## What should you ask AnyMind before you sign?
+
+1. What share do you keep, and is it the same for every ad format?
+2. When are you paid, and what's the minimum?
+3. Must AnyManager be your only ad partner?
+4. How much notice do you need to give to leave?
+
+## What if you want public terms first?
+
+[Google AdSense](/ad-networks/google-adsense) has no traffic minimum and publishes its share. [Ezoic](/ad-networks/ezoic) publishes a minimum share in its terms. [Sovrn](/ad-networks/sovrn) publishes its traffic bar and a $25 payment minimum.
## How can you check if a site uses AnyManager?
-Look for AnyManager in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to AnyManager.
+Look for AnyManager in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/joining.mdx
index 7b6b4bd5..fc176893 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/anymind-anymanager/joining.mdx
@@ -1,3 +1 @@
-## Who can join AnyManager?
-
-Not public. AnyMind doesn't publish a traffic minimum, site rules, accepted regions, or how to apply.
+AnyMind doesn't publish a traffic minimum, site rules, accepted regions, or how to apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/article.mdx
index 76c49f9e..a2c1079e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/article.mdx
@@ -1,11 +1,23 @@
## Who is Carbon Ads for?
-Sites that want an ad built to match their design. Its terms aren't public, so contact BuySellAds to see if your site fits.
+Sites that want one ad built to match their design, instead of standard banner slots. Carbon Ads builds each unit to fit the publisher's site. BuySellAds reviews your traffic, how well its ads fit your readers, and whether the site is kept up. Demand is strongest for developer and design sites.
## What's the difference between BuySellAds and Carbon Ads?
BuySellAds is the company. Carbon Ads is one of its ad programs for publishers.
+## How do you add Carbon Ads to your site?
+
+Through the Carbon tag or its API. The API route suits you if you want to control exactly how the ad is drawn on your page.
+
+## What should you ask before you sign?
+
+Your share, since it isn't public. Ask too how much notice you need to leave. Carbon must be the only ad network on your site, so drop any others first.
+
+## What's similar if Carbon Ads doesn't reply?
+
+[EthicalAds](/ad-networks/ethicalads) also shows one ad that fits the page, and it publishes its share and payment minimum. It suits developer and open source sites.
+
## How can you check if a site uses Carbon Ads?
-Look for Carbon Ads in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Carbon Ads.
+Look for Carbon Ads in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/intro.mdx
index ee82c07b..164f147b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/intro.mdx
@@ -1 +1 @@
-Carbon Ads, from BuySellAds, places ads built to fit each site's design. Its joining rules and pay terms are not public.
+Carbon Ads, from BuySellAds, places ads built to fit each site's design. It reviews each application and publishes when and how it pays, but not the publisher share.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/joining.mdx
index 515a9ab5..84187b5f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Carbon Ads?
+BuySellAds reviews each site's monthly pageviews, how well its ads fit your readers, and whether the site is kept up to date. It doesn't set a fixed traffic minimum.
-Not public. The Carbon Ads media kit doesn't give a traffic minimum, site rules, regions, or how to apply.
+Demand is strongest for English-speaking developer and design readers. That's where advertisers spend most, not a closed list of countries.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/pay.mdx
index 53ded92c..467e2ec3 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/pay.mdx
@@ -1,3 +1,5 @@
## How does Carbon Ads pay?
-Not public. The media kit doesn't give the publisher share, when payments go out, the minimum, methods, or currency.
+Each month's earnings land in your BuySellAds account after the month ends, and you can withdraw them some weeks later. Each withdrawal method has its own minimum, so pick one your earnings clear. Open Collective payouts run quarterly when you ask for them.
+
+The publisher share and currency are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/rules.mdx
index b1d32947..f0bbdcf1 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/buysellads-carbon-ads/rules.mdx
@@ -1,3 +1,3 @@
## What rules does Carbon Ads set?
-Carbon Ads builds each ad unit to fit the publisher's design. Exclusivity, content rules, contract length, and notice are not public.
+Carbon is an exclusive network. Once you join, you show only Carbon ads on your site, and you can't use Carbon as backfill for another network. Carbon Ads builds each ad unit to fit the publisher's design. Contract length and notice are not in its FAQ.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/article.mdx
index 4a86b163..72ac0291 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/article.mdx
@@ -1,15 +1,26 @@
## Is Clickio a fit for a site outside the US?
-It can be. Clickio sets its traffic bar by visitor region, with rules for readers across Europe, Latin America, and elsewhere. The bar is higher outside its main markets.
+It can be. Clickio sets its traffic bar by visitor region, with rules for readers across Europe, Latin America, and elsewhere. The bar is lowest for the UK, France, the US, Canada, and Australia. Sites in sanctioned countries can't join.
## What if your traffic is below Clickio's bar?
-Clickio may still take your site if it already earns enough from ads. Revenue counts as well as pageviews, so mention your earnings when you apply.
+Clickio may still take your site if it earns enough from ads. Revenue counts as well as pageviews, so mention your earnings when you apply. Keep in mind the earnings rule can also apply after you join, not only at the start.
+
+## What should you have ready before you apply?
+
+1. GA4 access, or a six-month traffic report if Clickio can't verify your traffic another way.
+2. An ads.txt file you can edit.
+3. An IAB-approved consent tool on your site.
+4. Content you own or have rights to, that follows AdSense policies.
## Can you keep other ad partners with Clickio?
Clickio's entry rules don't say it must be your only partner. Confirm what your agreement says before you add others.
+## Where else can a smaller or global site go?
+
+[Publift](/ad-networks/publift) looks at ad revenue first and works best with most readers in the Americas, Europe, or Australia and New Zealand. [Google AdSense](/ad-networks/google-adsense) has no traffic minimum. Networks like [Raptive](/ad-networks/raptive) and [Monumetric](/ad-networks/monumetric) want a large share of readers in a few English-speaking countries.
+
## How can you check if a site uses Clickio?
-Look for Clickio in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Clickio.
+Look for Clickio in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/intro.mdx
index 7d4e8c71..877c2b52 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/intro.mdx
@@ -1 +1 @@
-Clickio is an ad platform that can run a site's ads as a fully managed service. It takes sites from many regions, with a traffic bar that depends on where readers are.
+Clickio is an ad platform that can run a site's ads as a fully managed service. It works with sites in many regions, and its traffic bar depends on where readers are.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/joining.mdx
index 0958b2e4..1ccc21a9 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/joining.mdx
@@ -1,5 +1,5 @@
-## Who can join Clickio?
-
The traffic Clickio wants depends on where your visitors are. Sites with readers in the UK, France, the US, Canada, or Australia have the lowest bar, and other regions need more. A smaller site can still qualify if it earns enough from ads.
-You need six months of history, original content you have rights to, and good standing with Google's policies. Adult, shocking, and racially intolerant content isn't allowed. Clickio also lists sanctioned countries it can't work with, including Cuba, Iran, Syria, Russia, and Sudan.
+Your content must be yours or licensed, and it must follow AdSense policies. Adult, shocking, and racially intolerant content isn't allowed. Clickio also lists sanctioned countries it can't work with, including Cuba, Iran, Syria, Russia, and Sudan.
+
+You'll add Clickio's ads.txt lines and use an IAB-approved consent tool. Clickio checks your traffic through GA4 or another independent source. If it can't, it asks for a six-month traffic report instead.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/pay.mdx
index 7ac79a63..bd586ead 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/clickio/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/clickio/pay.mdx
@@ -1,5 +1,5 @@
## How does Clickio pay?
-Clickio bills monthly and pays on Net 60, around the 25th to 30th, two months after the month you earn. The minimum depends on how you're paid, and some methods can pay in your local currency.
+Clickio bills monthly and pays around the 25th to 30th of the month payment is due. The help page gives one timing for everyone. The publisher agreement also offers a faster option, but only for demand partners that pay that fast. The minimum depends on how you're paid, and some methods can pay in your local currency.
-Its standard share is not public.
+There's no fixed share. Your commission depends on the rates and events each advertiser picks.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/concert/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/concert/article.mdx
index d122ea08..dff44d32 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/concert/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/concert/article.mdx
@@ -1,11 +1,19 @@
## What is Concert?
-Concert is a publisher-led advertising marketplace run by Vox Media. The terms on its site are for advertisers who buy ads through it.
+Concert is a publisher-led advertising marketplace run by Vox Media. The terms on its site are for advertisers who buy ads through it, not for publishers.
## Can any site join Concert?
Concert doesn't publish publisher rules or an application form. Contact its team to ask.
+## What should you ask Concert before you sign?
+
+Ask for your share, when you're paid, the payment minimum, and whether Concert must be your only ad partner. Ask who decides where ads go and how much notice you need to leave. None of this is public, so get it in writing.
+
+## What if you want an open application instead?
+
+Pick a network that publishes its entry rules. [Google AdSense](/ad-networks/google-adsense) has no traffic minimum. [Raptive](/ad-networks/raptive) and [Mediavine](/ad-networks/mediavine) publish their entry rules, share, and pay day.
+
## How can you check if a site uses Concert?
-Look for Concert in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Concert.
+Look for Concert in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/concert/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/concert/joining.mdx
index 6f0bfbd4..1aa2cd7f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/concert/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/concert/joining.mdx
@@ -1,3 +1 @@
-## Who can join Concert?
-
-Not public. The Concert terms we found cover advertisers buying ads, not publishers joining. Traffic, content rules, regions, and how to apply are not published.
+The Concert terms we found cover advertisers buying ads, not publishers joining. Traffic, content rules, regions, and how to apply are not published.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/article.mdx
index 11f53005..b9e80897 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/article.mdx
@@ -2,14 +2,24 @@
It suits developer and open source sites that want one clean ad instead of many. It won't fit a page that needs several ad slots, because EthicalAds must be the only ad on that page.
+## What should you check before you apply?
+
+Make sure you have a spot for the ad above the fold, on both desktop and mobile. EthicalAds also expects a minimum click-through rate, so a spot readers actually see matters. You'll also need about 50,000 pageviews a month, though EthicalAds may make an exception for a high-quality or growing site.
+
## Can you run EthicalAds with another network?
Yes, as long as they never share a page. EthicalAds lets you split your visitors with another network, or set a fallback ad.
-## Where should the EthicalAds ad go?
+## How does EthicalAds pay compare with AdSense?
+
+You keep 70%, with a $50 minimum. [Google AdSense](/ad-networks/google-adsense) shows 80%, but that's after its platform fee, and it works out to about 68% for Google Ads demand. Its minimum is $100 in US dollars.
+
+If your project already takes donations, EthicalAds can pay you through OpenCollective or GitHub Sponsors.
+
+## What's similar to EthicalAds?
-Above the fold, on both desktop and mobile. That's what the policy asks for, along with a minimum click-through rate.
+[Carbon Ads](/ad-networks/buysellads-carbon-ads) also runs one ad built to fit the page. It publishes when and how it pays, but not your share, so you'd need to ask. Carbon must be the only ad network on your site.
## How can you check if a site uses EthicalAds?
-Look for EthicalAds in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to EthicalAds.
+Look for EthicalAds in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/joining.mdx
index 2d5dc0fa..2341a1bd 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/ethicalads/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join EthicalAds?
-
-There's no traffic minimum. You need an approved account, and your site has to meet the publisher policy.
+EthicalAds is for developer-focused sites. It sets a traffic minimum, but may make an exception for a high-quality or growing site. Once you're approved, you install the EthicalAds ad client, and your site has to meet the publisher policy.
The ad should sit above the fold on desktop and mobile. EthicalAds expects a click-through rate of at least 0.1%.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/article.mdx
index 8869deec..2bde1087 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/article.mdx
@@ -1,15 +1,23 @@
+## Who is Ezoic a fit for now?
+
+Large sites. New sites need a lot of monthly users to join the main program, and the content must be original, in a supported language, and follow AdSense policies. You don't need AdSense approval first for most sites.
+
## Can a small site still join Ezoic?
Not as a new site on the main program. New sites below the traffic rule can apply to the Ezoic Incubator instead. Sites already earning with Ezoic before the rule changed can stay.
-## Why do Ezoic's payment dates look different in different places?
+## What should you have ready before you apply?
+
+Google Analytics on your site, since Ezoic uses it to check your traffic. Your visitors need to be real people, not bots.
+
+## How does Ezoic's share compare?
-Ezoic's legal terms and its payment help page describe the timing differently. The terms are the contract, so we show those. Ask Ezoic to confirm your schedule before you count on a date.
+The terms give you at least 82% of net ad revenue, and the minimum payout is $20. That share is of net revenue, so don't compare it head to head with a share of gross. Ask Ezoic what's taken out before the split.
-## What content does Ezoic accept?
+## Where can you go if Ezoic says no?
-Original content that follows AdSense policies, with visitors who are real people rather than bots.
+[Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month. [Monumetric](/ad-networks/monumetric) and [Raptive](/ad-networks/raptive) take smaller sites, if a large share of readers are in the US or a few other English-speaking countries. [Google AdSense](/ad-networks/google-adsense) has no traffic minimum.
## How can you check if a site uses Ezoic?
-Look for Ezoic in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Ezoic.
+Look for Ezoic in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/joining.mdx
index bf0fbba3..0c84a700 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/ezoic/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Ezoic?
-
Ezoic set its current traffic rule for new sites in February 2026. Sites already earning with Ezoic before February 19, 2026 can keep going under the old rule. Smaller sites can apply to the Ezoic Incubator.
Your content must be original and follow AdSense policies, and your traffic must come from real people.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/freestar/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/freestar/article.mdx
index 33284ead..e04f58a0 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/freestar/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/freestar/article.mdx
@@ -2,14 +2,25 @@
Only once it's large. Freestar usually works with high-traffic sites, and it checks where your readers are. A site with most readers outside the US, UK, Canada, New Zealand, and Australia won't meet the rule, even if it's big.
+## What should you have ready before you apply?
+
+1. GA4 access to share during review.
+2. Your past traffic and revenue numbers.
+3. Original content made for people, and brand safe.
+4. Good standing with major ad providers.
+
## How long does it take to start with Freestar?
-Plan for several weeks. An account manager and a technical team guide the setup.
+Plan for several weeks. Freestar says onboarding commonly takes three to six weeks, with an account manager and a technical team guiding the setup.
+
+## What should you ask before you sign?
+
+Your share, pay day, payment minimum, and whether Freestar must be your only ad partner. None of these are public. Ask how much notice you need to leave, too.
-## What does Freestar check before it accepts you?
+## What fits if you're not at Freestar's size yet?
-Your content, your standing with ad providers, and where your traffic comes from. It may ask for GA4 access and your traffic and revenue history.
+[Raptive](/ad-networks/raptive) has a much lower pageview bar with a similar location rule. [Playwire](/ad-networks/playwire) asks for less traffic and looks for a good footprint in English-speaking countries, not a set share. [Mediavine](/ad-networks/mediavine) looks at yearly ad revenue instead of pageviews.
## How can you check if a site uses Freestar?
-Look for Freestar in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Freestar.
+Look for Freestar in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/freestar/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/freestar/joining.mdx
index 07af2203..c9e97049 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/freestar/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/freestar/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Freestar?
-
Freestar's traffic rule is what it usually asks for, not a strict cutoff, so ask its team if you're close. At least 50% of your traffic must come from the US, UK, Canada, New Zealand, or Australia.
Your content must be original and made for people, and you need good standing with major ad providers. Explicit sexual content, piracy, violence, hate speech, and illegal drugs aren't allowed.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/article.mdx
index 4c36ee4a..549ef9df 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/article.mdx
@@ -4,8 +4,16 @@ A supply-side platform (SSP) sells a publisher's ad space to many buyers at once
## How do you join Geniee SSP?
-Geniee doesn't publish an application route for publishers. Contact Geniee to ask.
+Sign up through Geniee's online publisher form. Its terms of use set the content rules and how you're paid.
+
+## What should you ask Geniee before you sign?
+
+Your share, since Geniee doesn't publish a fixed one. Also ask how much notice you need to give to leave, since the terms only say how Geniee can end the agreement.
+
+## What else can you join with public rules?
+
+[Google AdSense](/ad-networks/google-adsense) has no traffic minimum. [Sovrn](/ad-networks/sovrn) runs an ad exchange for sites with more than 100,000 visits a month, with a $25 payment minimum.
## How can you check if a site uses Geniee SSP?
-Look for Geniee SSP in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Geniee SSP.
+Look for Geniee SSP in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/intro.mdx
index 3a8ff7be..abf46e44 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/intro.mdx
@@ -1 +1 @@
-Geniee SSP is a supply-side platform run by Geniee. It sells publishers' ad space to buyers, and its publisher rules and terms are not public.
+Geniee SSP is a supply-side platform run by Geniee. It sells publishers' ad space to buyers, and you sign up through an online publisher form.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/joining.mdx
index 8259998f..381dfd36 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Geniee SSP?
+Geniee doesn't publish a traffic minimum or the regions it accepts. You sign up through its online publisher form, and its terms of use set the content rules.
-Not public. Geniee doesn't publish a traffic minimum, site rules, accepted regions, or how to apply.
+Once you're in, you install Geniee's ad tags and keep them on your site.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/pay.mdx
index 9778233a..435bb99e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/pay.mdx
@@ -1,3 +1,5 @@
## How does Geniee SSP pay?
-Not public. The share, payment timing, minimum, methods, and currency aren't on Geniee's public pages.
+Geniee works out your earnings the month after you earn them, then pays by the end of the second month after that. It only pays once the advertiser has paid Geniee, so a late advertiser can delay your money.
+
+The minimum is higher for a wire transfer than for PayPal or Payoneer. Geniee doesn't publish a fixed share.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/rules.mdx
index 3f137ecf..4a767058 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/geniee-ssp/rules.mdx
@@ -1,3 +1,5 @@
## What rules does Geniee SSP set?
-Not public. Exclusivity, ad placement, content rules, contract length, and notice aren't on Geniee's public pages.
+Geniee's terms of use set the content rules, and you must keep its tags in place. You tell Geniee where you'll place ads. If it asks for changes and you can't agree, Geniee decides the placement. You also must tell Geniee before you use a similar service alongside it, or replace it with one.
+
+The agreement runs from the day Geniee approves you until it ends. Geniee can end it with 30 days' notice, or at once if you break the terms. The terms don't say how much notice you must give to leave.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/article.mdx
index 6e1527d3..723e9be7 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/article.mdx
@@ -1,15 +1,23 @@
## Is AdSense a good first ad network?
-For many new sites it's the easiest start. There's no traffic minimum, and you set it up yourself in your AdSense account.
+For many new sites it's the easiest start. There's no traffic minimum, and you set it up yourself in your AdSense account. Help comes through the AdSense Help Center, so you place and tune ads on your own.
+
+## What should you check before you apply?
+
+Make sure your content is original and follows the AdSense Program Policies, and that you can edit your site's HTML to add the code. Check that AdSense, and a payment method you can use, are available in your country. Review usually takes a few days, but can take two to four weeks.
+
+## When will you see your first payment?
+
+Only once your balance passes the minimum. If you earn $20 a month, that's five months before your first payment. After that, Google pays once a month.
## Can you use AdSense with another network?
-AdSense doesn't ask to be your only ad partner. Some managed networks do, so check their rules before you add one.
+AdSense doesn't ask to be your only ad partner. Some managed networks do, such as [Newor Media](/ad-networks/newor-media)'s Elevate program and [Playwire](/ad-networks/playwire), so check their rules before you add one.
-## Why do you earn less than the share Google shows?
+## Where can you go once you outgrow AdSense?
-The share applies after the advertiser platform fee. For ads bought through Google Ads, your cut of what the advertiser paid ends up lower than the headline share.
+[Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month. [Monumetric](/ad-networks/monumetric)'s Propel program starts at 10,000 monthly pageviews and [Raptive](/ad-networks/raptive) at 25,000. Both want a large share of readers in the US and a few other English-speaking countries. [Mediavine](/ad-networks/mediavine) looks at yearly ad revenue instead of traffic.
## How can you check if a site uses Google AdSense?
-Look for Google AdSense in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Google AdSense.
+Look for Google AdSense in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/intro.mdx
index 8e8db26c..70717d07 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/intro.mdx
@@ -1 +1 @@
-Google AdSense is Google's ad program for website publishers. It has no traffic minimum, so it suits new and small sites.
+Google AdSense is Google's ad program for website publishers. You add its code to your site and run your ads yourself from your AdSense account.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/joining.mdx
index d861bd81..1b7abed4 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/google-adsense/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Google AdSense?
-
You must be at least 18, own original content that follows AdSense policies, and be able to edit your site's HTML. There's no traffic minimum.
You sign up in an AdSense account. Whether AdSense is open to you, and how you can be paid, depends on your country.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/article.mdx
index f1584836..c90e43eb 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/article.mdx
@@ -1,11 +1,23 @@
## Is Infolinks a fit for a small site?
-It can be. Infolinks is open to sites of any size, so it can work before you qualify for a managed network.
+It can be. Infolinks is open to sites of any size, so it can work before you qualify for a managed network. It won't take illegal, offensive, adult, or porn content.
-## How current are Infolinks' public terms?
+## How long does Infolinks take to approve you?
-The public agreement is years old. Ask Infolinks for the current version before you rely on its numbers.
+Usually about 48 hours after you send its short sign-up form. Once approved, you add the Infolinks script to your site.
+
+## What are in-text ads?
+
+Ads that sit inside your words. Infolinks links some words in your text, and an ad appears when a reader hovers over one. You can change how they look and how many show.
+
+## Can you try Infolinks before you commit?
+
+The old public agreement starts with a 30-day trial, then renews every 12 months. It can be ended on one business day's notice. That agreement was last updated in 2015, so ask whether the current one still works this way.
+
+## What else can a small site try?
+
+[Google AdSense](/ad-networks/google-adsense) has no traffic minimum. [Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month.
## How can you check if a site uses Infolinks?
-Look for Infolinks in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Infolinks.
+Look for Infolinks in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/intro.mdx
index 41990089..f06d2c84 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/intro.mdx
@@ -1 +1 @@
-Infolinks runs in-text ads and other ad units for websites. Publishers of any size can apply.
+Infolinks runs in-text ads and other ad units for websites. It reviews new sites within 48 hours.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/joining.mdx
index f0c60dc2..70ac7831 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Infolinks?
-
Any size of site can apply, and there's no traffic minimum. Infolinks reviews each site and may reject it.
Illegal, negative, offensive, adult, obscene, and porn content isn't allowed. You sign up with a short web form, and review usually takes 48 hours.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/pay.mdx
index c0af55b9..ccc7fb2c 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/infolinks/pay.mdx
@@ -1,5 +1,5 @@
## How does Infolinks pay?
-The public agreement gives you 70% for In-Text ads and pays 45 working days after the month ends. Other ad formats have different shares and minimums.
+The public agreement gives you 70% for In-Text ads and pays 45 working days after the month ends. Other ad formats have different shares. The payment minimum depends on the method you pick.
That agreement was last updated in 2015. If you sign a newer one, the newer terms count.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/article.mdx
index d1c359ad..e9ef6091 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/article.mdx
@@ -1,11 +1,26 @@
+## Who is Journey a fit for?
+
+Bloggers and small content sites that have started to get steady traffic. The bar is 1,000 premium sessions a month. Your content has to be original, made by people, updated, and brand safe.
+
## How is Journey different from Mediavine?
-Journey is for sites still growing, with a much lower bar to join. [Mediavine](/ad-networks/mediavine)'s main program is for sites that already earn steady ad revenue. Journey's pay and rules aren't public, so don't assume they match Mediavine's.
+Journey is for sites still growing, with a much lower bar to join. [Mediavine](/ad-networks/mediavine)'s main program is for sites that already earn steady ad revenue. Journey pays a 70% share, below the main program's tiers, on the same Net 65 timing. Its other rules aren't public, so don't assume they match Mediavine's.
+
+## What should you have ready before you apply?
+
+1. The Grow plugin installed and running for at least 30 days.
+2. A clean record with Google, with no active AdSense or Ad Exchange issues.
+3. A domain with about four months of history, which Journey says its ad partners expect.
+4. A clear picture of your traffic: where it comes from, which countries, and who reads you.
+
+## What should you ask before you sign?
+
+Journey's payment minimum and payment methods aren't public. Ask for them, and ask whether Journey must be your only ad partner.
-## What does Mediavine check when you apply to Journey?
+## What else fits a site this size?
-Your traffic sources, the countries your visitors come from, and who your readers are. It also wants original, brand-safe content made by people.
+[Google AdSense](/ad-networks/google-adsense) has no traffic minimum. [Monumetric](/ad-networks/monumetric)'s Propel program starts at 10,000 monthly pageviews for English sites.
## How can you check if a site uses Journey by Mediavine?
-Look for Journey by Mediavine in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Journey by Mediavine.
+Look for Journey by Mediavine in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/joining.mdx
index 59e9a7e8..bf1ce98e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Journey by Mediavine?
-
Journey's traffic bar is low. Your content must be original, updated often, made by people, and brand safe, with an engaged audience.
-Mediavine looks at your traffic sources, visitor countries, and reader demographics. You need the Grow plugin on your site. Journey doesn't say which regions it accepts.
+Mediavine looks at your traffic sources, visitor countries, and reader demographics. You need the Grow plugin running on your site so Journey can collect data for its review. It takes sites from anywhere Mediavine does business. Journey also expects some domain history, because its ad partners ask for it.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/pay.mdx
index e77eaffe..f6815901 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/journey-by-mediavine/pay.mdx
@@ -1,3 +1,5 @@
## How does Journey by Mediavine pay?
-Not public. Journey's share, payment timing, minimum, methods, and currency aren't published. Mediavine's main program terms don't apply to Journey.
+Journey publishes its share and payment timing. Its share is lower than the main Mediavine program pays, and the timing matches it.
+
+The payment minimum, methods, and currency for Journey aren't published. Don't assume Mediavine's main program minimum and methods apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/article.mdx
index 5d6d16cd..2fd0562d 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/article.mdx
@@ -1,11 +1,25 @@
+## Who is Media.net a fit for?
+
+Sites you own and run, with real, unpaid traffic and original content. Media.net checks for bought or invalid traffic, and too much of it can get your account suspended. If another ad provider has suspended or dropped you before, Media.net won't take you.
+
## What is a contextual ad?
It's an ad picked for the words on the page, not for the person reading it. A page about hiking shows hiking ads.
-## Who is Media.net a fit for?
+## What should you have ready before you apply?
+
+An ads.txt file with Media.net's lines in it, and accurate details about your site. Check its inventory policy for the topics it doesn't allow.
+
+## How fast does Media.net pay?
+
+It pays monthly on Net 30, so a month's earnings arrive about a month after it ends. That's faster than many managed networks here, such as [Mediavine](/ad-networks/mediavine) on Net 65.
+
+Your pay is based on valid clicks, so earnings depend on readers clicking ads, not only seeing them.
+
+## What should you ask before you sign?
-Sites you own and run, with real, unpaid traffic. Media.net checks for bought or invalid traffic, and too much of it can get your account suspended.
+Your share and the payment minimum. Neither is public.
## How can you check if a site uses Media.net?
-Look for Media.net in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Media.net.
+Look for Media.net in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/joining.mdx
index d3b3ad7d..e4d6075a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/joining.mdx
@@ -1,5 +1,5 @@
-## Who can join Media.net?
-
Media.net doesn't publish a traffic minimum or accepted regions. Its agreement covers sites you own, run, or control, and you apply through its publisher program.
-Its inventory policy bans invalid or bought traffic above acceptable levels. Your ad requests and site details must be accurate.
+Most of your traffic must be organic, and its inventory policy bans invalid or bought traffic above acceptable levels. Your ad requests and site details must be accurate.
+
+You can't have been suspended or dropped by another ad provider before. The agreement also asks you to tell Media.net about certain past traffic or policy suspensions.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/rules.mdx
index 5016400e..e5063d35 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/media-net/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/media-net/rules.mdx
@@ -2,4 +2,4 @@
You agree to keep Media.net's confidential information private. Media.net can suspend or end your account for policy problems.
-The agreement doesn't state an exclusivity rule, placement rules, or a fixed contract term.
+You can't run another service that shows ads substantially similar to Media.net's. The agreement doesn't set placement rules or a fixed contract term.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/article.mdx
index 47eefbbc..5e7f405e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/article.mdx
@@ -1,6 +1,12 @@
-## How do you join Mediavine?
+## Who is Mediavine a fit for?
-You apply with your site, and Mediavine reviews your ad revenue, traffic, and content against the rules here. If you're approved, you add their script and their ads.txt lines, and they set up and run the ads for you.
+Content sites that already earn steady ad revenue, often in food, travel, home, and similar topics. Mediavine looks at what you earn from ads in a year across all your sites, not a traffic number. Your content needs to be original, high quality, and evergreen.
+
+## What should you have ready before you apply?
+
+Proof of what your ads earn now, since the bar is yearly ad revenue. You'll also need to give Mediavine read-only Google Analytics access during review.
+
+You must be in good standing with AdSense and Ad Exchange, with no active policy issues. You don't need to have used AdSense before.
## What if your site is too small for Mediavine?
@@ -10,9 +16,9 @@ Mediavine runs a second program, [Journey](/ad-networks/journey-by-mediavine), f
Mediavine pays each month's earnings a set number of days after the month ends. Earnings from January arrive a couple of months later, not at the start of February. Plan for that gap if you switch from a network that pays faster.
-## Can you run other ads with Mediavine?
+## How does Mediavine compare with Raptive?
-Mediavine's help center lists its rules on ad placement and other ad partners. Affiliate links and sponsored posts are usually separate, but check the current rules with Mediavine before you sign.
+Raptive publishes a 75% share. Mediavine's starts at 75% for new sites and rises to 90% in its top tiers. [Raptive](/ad-networks/raptive) sets a pageview bar and a reader location rule, while Mediavine sets a revenue bar. Raptive pays on Net 45, sooner than Mediavine's Net 65. Mediavine says there's no long-term contract.
## How can you check if a site uses Mediavine?
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/joining.mdx
index da15ec41..bfbfac3d 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/mediavine/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Mediavine?
-
Mediavine Official is for sites that already earn steady ad revenue. When you apply, Mediavine reviews both your traffic and your content.
Your content needs to be original, high quality, and evergreen. If your site is still growing, [Journey](/ad-networks/journey-by-mediavine) is Mediavine's separate program for newer sites.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/mgid/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/mgid/article.mdx
index 40ba4da4..ec5baacb 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/mgid/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/mgid/article.mdx
@@ -1,11 +1,23 @@
+## Who is MGID a fit for?
+
+Sites that want native ads, the kind that look like content links, alongside or instead of banners. MGID's main service asks for at least 3,000 unique visitors a day. Its separate Google Discover offer says it has no minimum. Either way, your site has to pass its traffic quality and content rules. Adult, illegal, hateful, and infringing content isn't allowed.
+
## Why does MGID's share depend on the offer?
MGID sets pay in each publisher's order, not in one public rate card. The share in one regional offer may not be what you're offered, so compare the order you get.
-## Does MGID take small sites?
+## Which payment method should you pick?
+
+One with a minimum your earnings clear. MGID's minimums range from $50 to $1,000 depending on the method, so a small site can wait a long time on a high one.
+
+## What could get your MGID account in trouble?
+
+Invalid traffic. MGID's terms cover it, and they say your revenue can be adjusted. Don't buy traffic or encourage clicks.
+
+## What else runs native ads?
-It doesn't publish a single traffic minimum, and its Discover program says it has none. Your site still has to pass its quality rules.
+[Taboola](/ad-networks/taboola) and [Revcontent](/ad-networks/revcontent) both run recommendation and native ads. Taboola must be your only recommendation service while your deal runs.
## How can you check if a site uses MGID?
-Look for MGID in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to MGID.
+Look for MGID in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/mgid/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/mgid/joining.mdx
index 2ea8da0f..70363ed6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/mgid/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/mgid/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join MGID?
-
-MGID doesn't publish one traffic minimum or region rule. Your site has to meet its traffic quality and content rules. You apply through its publisher sign-up or contact page.
+MGID sets a daily visitor minimum for its main service, and it emails you a yes or no soon after you apply. It doesn't publish a region rule. Your site also has to pass its traffic quality and content rules. You apply through its publisher sign-up or contact page.
MGID's separate Google Discover offer says it has no traffic minimum, but that applies only to that program.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/article.mdx
index 3601facd..367694cb 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/article.mdx
@@ -1,11 +1,23 @@
+## Who is PubGuru Premium a fit for?
+
+Sites that already earn well from ads or get heavy traffic. You qualify on either monthly ad revenue or monthly pageviews, counted across your sites.
+
## What's the difference between MonetizeMore and PubGuru?
MonetizeMore is the company. PubGuru is its ad platform, and PubGuru Premium is the higher tier with extra tools and a support team.
## Is PubGuru Premium a fit for a smaller site?
-Not yet. Premium is for sites with high ad revenue or traffic. Ask MonetizeMore what it offers below that level.
+Not yet. Ask MonetizeMore what it offers below the Premium level. [Publift](/ad-networks/publift) also qualifies sites on ad revenue, with a lower bar. [Mediavine](/ad-networks/mediavine) uses a yearly ad revenue bar.
+
+## What should you have ready before you contact MonetizeMore?
+
+Your monthly ad revenue and pageviews for every site you'd bring. If you run several sites, add them up, since Premium counts them together.
+
+## What should you ask before you sign?
+
+Your exact share, pay day, payment minimum, and how much notice you need to leave. None of these are on the Premium page. Ask whether you can keep other ad partners.
## How can you check if a site uses MonetizeMore?
-Look for MonetizeMore in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to MonetizeMore.
+Look for MonetizeMore in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/joining.mdx
index c0cff58a..4104123a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join PubGuru Premium?
-
PubGuru Premium needs either $5,000 in monthly ad revenue or 2 million monthly pageviews across your sites. MonetizeMore's FAQ mentions only the revenue rule, but the Premium page gives both.
You start by contacting MonetizeMore. The Premium page doesn't list a location rule.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/pay.mdx
index ac277ce3..576ff8b0 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monetizemore-pubguru/pay.mdx
@@ -1,5 +1,7 @@
## How does MonetizeMore pay?
-Not public. The Premium page doesn't give the share, payment schedule, minimum, methods, or currency.
+MonetizeMore works on a performance-based revenue share that it sets for each publisher. It doesn't publish the Premium rate.
+
+The payment schedule, minimum, methods, and currency are not public.
MonetizeMore's Traffic Cop product has its own payment terms, which don't cover PubGuru.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/article.mdx
index 17a8f36c..2fbdbd34 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/article.mdx
@@ -1,11 +1,23 @@
## Is Monumetric a fit for a new blog?
-It can be, if you write in English and your readers are mainly in the US, UK, Canada, or Australia. Propel is its program for smaller sites.
+It can be, if you write in English and your readers are mainly in the US, UK, Canada, or Australia. Propel is its program for smaller sites, and its pageview bar is lower than most managed networks that publish one.
+
+## Who won't Monumetric take?
+
+Sites with most readers outside those four countries, sites not in English, and sites with porn, drugs, hate speech, or copied content.
## When does Monumetric pay you?
A couple of months after you earn it, early in the month. Small balances carry over until they pass the minimum.
+## How does Monumetric compare with Raptive and Journey?
+
+[Journey by Mediavine](/ad-networks/journey-by-mediavine) has a lower bar, 1,000 premium sessions a month. [Raptive](/ad-networks/raptive) asks for more pageviews but publishes a 75% share and pays on Net 45. Monumetric doesn't publish its share.
+
+## What should you ask before you sign?
+
+Your share, whether Monumetric must be your only ad partner, and how much notice you need to leave. None of these are on its public pages.
+
## How can you check if a site uses Monumetric?
-Look for Monumetric in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Monumetric.
+Look for Monumetric in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/joining.mdx
index e5da3dbd..f3c1ea47 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Monumetric?
-
Your content must be in English, and at least 50% of your traffic must come from the US, UK, Canada, or Australia. Monumetric won't take content that harms its brand, such as porn, drugs, hate speech, or copyrighted material.
You apply through its program page.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/pay.mdx
index 63751522..c2d2dc68 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/monumetric/pay.mdx
@@ -2,4 +2,4 @@
Monumetric pays on Net 60, within the first ten business days of the month. If your balance is under the minimum, it rolls into the next month.
-US publishers are paid by direct deposit, and international publishers by PayPal. Payoneer can count as a US bank account in some cases. The share and currency are not public.
+US publishers are paid by direct deposit, and international publishers by PayPal. The share and currency are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/article.mdx
index 9e2f478e..d3871d75 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/article.mdx
@@ -2,14 +2,27 @@
Start with Elevate if your site is new, since it has no stated traffic bar. Catapult and Premier are for sites with more US traffic.
-## Why are there two payment terms for Newor Media?
+## What should you have ready before you apply to Elevate?
-The FAQ and the platform agreement disagree. The signed agreement is your contract, so go by that, and ask Newor to confirm your dates.
+1. An English-language site with a navigation bar.
+2. Room for at least two ads on each page.
+3. Your own Google Ad Manager account.
+4. Content that follows Google's ad policies.
+
+Newor Media usually replies within 24 to 48 hours. That's when you hear back, not a promise of approval.
## Can you run other ads with Newor Media?
-Not other display networks on Elevate, which is exclusive. Read the agreement for your program before you add partners.
+Not other display networks on Elevate, which is exclusive. If you run [Google AdSense](/ad-networks/google-adsense) or another network now, plan to remove it. Read the agreement for your program before you add partners.
+
+## How do you leave Newor Media?
+
+The platform agreement starts with a 90-day term, then renews. Give written notice at least 14 days before the term ends, or you roll into the next one.
+
+## What if you don't want an exclusive deal?
+
+[Journey by Mediavine](/ad-networks/journey-by-mediavine) and [Monumetric](/ad-networks/monumetric) also take smaller sites, and neither states an exclusivity rule on its public pages. Ask to be sure.
## How can you check if a site uses Newor Media?
-Look for Newor Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Newor Media.
+Look for Newor Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/intro.mdx
index 825a0cfb..8f70ef9f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/intro.mdx
@@ -1 +1 @@
-Newor Media runs ads for publishers through a ladder of programs, from Elevate for new sites to Catapult and Premier for larger ones. It suits English-language sites on Google Ad Manager.
+Newor Media runs ads for English-language sites on Google Ad Manager. New sites start on Elevate, its entry program, and move up to Catapult and Premier as they grow.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/joining.mdx
index 1d1f96ff..419e56f0 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/newor-media/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Newor Media?
+Elevate, the entry program, has no stated pageview minimum. Your site must be in English, have a navigation bar, follow Google's ad policies, and have room for at least two ads per page. You need Google Ad Manager. Newor also looks at where your visitors come from, but doesn't set a country mix.
-Elevate, the entry program, has no stated pageview minimum. Your site must be in English, have a navigation bar, follow Google's ad policies, and have room for at least two ads per page. You need Google Ad Manager. Approval usually takes 24 to 48 hours.
-
-The larger programs set traffic rules: Catapult at 60,000 US pageviews a month, and Premier at 420,000.
+The stated wait is how soon Newor usually replies, not a promise of approval. The larger programs, Catapult and Premier, set US pageview minimums.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/article.mdx
index 97e44284..445b601f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/article.mdx
@@ -1,11 +1,23 @@
+## Who is NitroPay a fit for?
+
+Publishers who want their money fast. NitroPay reviews your traffic, where your visitors are, and your niche, but it doesn't publish a traffic minimum or a list of accepted regions.
+
## How fast does NitroPay pay?
-Faster than most networks on this list. Its docs describe payment about a week after the month, with no minimum beyond the transaction fee.
+Faster than most networks on this list. Its docs describe payment about a week after the month, with no minimum beyond the transaction fee. Many managed networks here pay on Net 60, such as [Monumetric](/ad-networks/monumetric) and [Playwire](/ad-networks/playwire).
## How long should you test NitroPay?
-NitroPay recommends a testing period of a few months before you judge results.
+NitroPay recommends a testing period of a few months before you judge results. Compare its results with what you earned before, over a similar stretch of time.
+
+## What should you ask before you sign?
+
+Your base share, contract length, and how much control you keep over ad placement. None of these are in its public docs.
+
+## Does NitroPay pay bonuses?
+
+Its bonus page lists share increases for some agreements. That's on top of the base share, not the starting rate, so ask whether you'd qualify.
## How can you check if a site uses NitroPay?
-Look for NitroPay in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to NitroPay.
+Look for NitroPay in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/joining.mdx
index 5d957cac..24c585a6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join NitroPay?
+NitroPay reviews how much traffic you have, where your visitors are, and what your site covers. It doesn't publish a traffic minimum or a list of accepted regions. Its guidelines bar adult, illegal, violent, and infringing content.
-Not public. NitroPay doesn't publish a traffic minimum, content rules, accepted regions, or application steps. Contact its team to apply.
+Once your site is accepted, you add Nitro's ad tags and link your Google Ad Manager account through Google MCM, Google's program for letting a partner sell your ads. Giving NitroPay access to your GA4 data can speed up review. You go live once enough ad buyers are set up for your site.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/pay.mdx
index 2e71101d..58b26c67 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/nitropay/pay.mdx
@@ -1,5 +1,5 @@
## How does NitroPay pay?
-NitroPay's docs say it pays on Net 7, with no minimum as long as your earnings cover the transaction fee. The base share, full list of methods, and currency are not public.
+NitroPay pays early each month, with no minimum as long as your earnings cover the transaction fee. It pays by local bank transfer in many countries, such as ACH in the US or SEPA in Europe, and by wire elsewhere. Its docs list which currency goes with some of these methods. The base share is not public.
A separate bonus page lists share increases for some agreements. That's a bonus, not the starting share.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/article.mdx
index 74e6dc9b..83851aba 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/article.mdx
@@ -1,11 +1,19 @@
+## Who is Opti Digital for?
+
+Publishers who want a partner to run Google Ad Manager. Its fit rules aren't public, so ask its team.
+
## What's the difference between Managed Inventory and Managed Account?
-Both are ways Opti Digital runs your Google Ad Manager setup. They're separate commercial deals with different payment timing. With Managed Account, Google pays its share of revenue on its own schedule.
+Both are ways Opti Digital runs your Google Ad Manager setup. They're separate commercial deals with different payment timing. With Managed Account, Google pays its share of revenue on its own schedule, so your money comes in two streams.
-## Who is Opti Digital for?
+## Which setup gets you paid sooner?
-Publishers who want a partner to run Google Ad Manager. Its fit rules aren't public, so ask its team.
+Managed Inventory pays on Net 45. Managed Account pays Net 60 for the demand Opti Digital handles. Your order sets the exact terms.
+
+## What should you ask before you sign?
+
+Your share, the payment minimum, and how you're paid. Ask whether Opti Digital must be your only ad partner, and how much notice you need to leave. None of this is on its help pages.
## How can you check if a site uses Opti Digital?
-Look for Opti Digital in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Opti Digital.
+Look for Opti Digital in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/joining.mdx
index 82652644..4d1221f7 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/opti-digital/joining.mdx
@@ -1,3 +1 @@
-## Who can join Opti Digital?
-
-Not public. Opti Digital doesn't publish a traffic minimum, site rules, regions, or an application checklist. Contact its team to talk about fit.
+Opti Digital doesn't publish a traffic minimum, site rules, regions, or an application checklist. Contact its team to talk about fit.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/article.mdx
index b5bfd452..d10627df 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/article.mdx
@@ -1,15 +1,26 @@
+## Who is Playwire a fit for?
+
+Established sites and apps with original content, clean traffic, and readers in English-speaking countries. It suits a publisher ready to hand all ad slots to one partner.
+
## How much traffic do you need for Playwire?
-Playwire's own pages give different answers, so check the Joining tab and ask its team. Quality matters too: it checks invalid traffic and your ad setup.
+At least 500,000 monthly pageviews, or 1,000 daily active users for an app. Its qualification guide gives other numbers, but those are advice on when Playwire pays off, not the entry rule. Quality matters too: it checks invalid traffic and your ad setup.
+
+## What should you have ready before you apply?
+
+1. HTTPS and a privacy policy on your site.
+2. Room for at least three ads per device.
+3. Invalid traffic at or below Playwire's limit.
+4. A clean record with Google and major ad providers.
## Can you run other networks with Playwire?
No. Playwire says other ad network tags can't run with its script. Plan to move your ad slots over to it.
-## Who decides where Playwire's ads go?
+## What fits if you're below Playwire's traffic?
-You do. Playwire recommends layouts, but publishers have the final say.
+[Raptive](/ad-networks/raptive) and [Monumetric](/ad-networks/monumetric) take smaller sites with a large share of readers in the US and a few other English-speaking countries. [Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month.
## How can you check if a site uses Playwire?
-Look for Playwire in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Playwire.
+Look for Playwire in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/joining.mdx
index a0c2a41f..c80e318c 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Playwire?
-
-Playwire's pages disagree on traffic. Its FAQ asks for 500,000 monthly pageviews, or 1,000 daily active users for an app. Its qualification page says publishers are typically advised to have 100,000 pageviews and 20% US traffic.
+Playwire's FAQ sets the traffic bar, with a separate one for apps. Its qualification guide gives other numbers, but those are advice on when Playwire pays off for you, not the entry rule. It looks for a good share of readers in English-speaking countries. More US traffic tends to earn more, but there's no US minimum.
You also need original content, invalid traffic at or below 7%, a privacy policy, HTTPS, and room for at least three ads per device. Apply through Playwire's onboarding form.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/pay.mdx
index b04a739e..73de84ff 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/playwire/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/playwire/pay.mdx
@@ -1,3 +1,3 @@
## How does Playwire pay?
-Playwire pays monthly on Net 60 terms and works on a revenue share. The share, minimum, methods, and currency are not public.
+Playwire pays monthly on Net 60 terms, in US dollars. You get a share of net revenue, and it's higher for ads sold through other buyers than for ads Playwire sells directly. The payment minimum and methods are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/article.mdx
index 7a26dd21..e98643f8 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/article.mdx
@@ -1,11 +1,23 @@
## Is PubFuture a fit for a small site?
-It may be. PubFuture doesn't publish a traffic minimum, so smaller sites can apply.
+Not a very small one. A 2025 PubFuture case study names 100,000 pageviews a month as its minimum. Its current pages don't list entry rules, so ask through its sign-up page if you're unsure.
+
+## How does PubFuture pay compare?
+
+Net 30 with a $50 minimum, which is quicker than the Net 60 many managed networks use. You can be paid by PayPal, Payoneer, bank transfer, or Bitcoin.
## Can you control which ads PubFuture shows?
Yes. PubFuture says you can block ads you don't want.
+## How quickly will you get help?
+
+PubFuture says its ad operations team replies within 24 hours.
+
+## What should you ask before you sign?
+
+Your share, whether PubFuture must be your only ad partner, and how much notice you need to leave. None of these are public.
+
## How can you check if a site uses PubFuture?
-Look for PubFuture in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to PubFuture.
+Look for PubFuture in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/intro.mdx
index a3215702..e9436ae5 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/intro.mdx
@@ -1 +1 @@
-PubFuture is a header bidding and ad monetization service for publishers. It doesn't publish a traffic minimum, so smaller sites can apply.
+PubFuture is a header bidding and ad monetization service for publishers. Its traffic minimum comes from a 2025 PubFuture case study, not a rules page.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/joining.mdx
index 8eee674a..173137fe 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubfuture/joining.mdx
@@ -1,3 +1 @@
-## Who can join PubFuture?
-
-PubFuture doesn't publish a traffic minimum, accepted regions, or a full content checklist. You apply through its sign-up page.
+The traffic minimum comes from a 2025 PubFuture case study, not a current rules page. Accepted regions and a full content checklist aren't public. You apply through its sign-up page.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/article.mdx
index a112ea47..8b9a9ff8 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/article.mdx
@@ -1,19 +1,19 @@
-## Does PubGalaxy take sites below its suggested traffic?
+## Is PubGalaxy still running?
-It can. The traffic level is a suggestion, not a hard rule, and each site is reviewed on its own.
+Not under its own name. Azerion bought PubGalaxy in 2021 and moved its publisher services under the Improve Digital name in September 2026. The pubgalaxy.com site now opens Improve Digital's site, so new publishers start there. Sites that already run PubGalaxy still name it in their ads.txt files, so we keep listing them here.
-## Why does PubGalaxy list two shares?
+## What does it take to join now?
-One covers ads sold through its ad partners, and a lower one covers direct deals. Both are minimums in the published terms.
+Its current joining rules aren't public. The old guide moved to Improve Digital's site, so ask Improve Digital about traffic and content rules before you apply.
-## What does PubGalaxy check before it accepts you?
+## Do PubGalaxy's old pay terms still apply?
-Your traffic history, your content, and any copyright claims against your site in Google's Transparency Report.
+Not for certain. Its old terms set one minimum share for ads sold through its ad partners and a lower one for direct deals. Improve Digital's pages don't confirm either for new publishers, so ask for the terms you'd get.
-## Is PubGalaxy still running?
+## What do you give up with PubGalaxy?
-Yes, as part of Improve Digital. Azerion bought PubGalaxy in 2021 and moved its publisher services under the Improve Digital name in September 2026. The pubgalaxy.com site now opens Improve Digital's site, so new publishers start there. Sites that already run PubGalaxy still name it in their ads.txt files, so we keep listing them here.
+Under its old terms, you let it manage your ad inventory, and it could make changes to improve the reader experience. If you want full control of your layout, ask what you can still decide.
## How can you check if a site uses PubGalaxy?
-Look for PubGalaxy in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to PubGalaxy.
+Look for PubGalaxy in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/intro.mdx
index dd81b891..f06d634a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/intro.mdx
@@ -1 +1 @@
-PubGalaxy is an ad revenue service that reviews each publisher one by one. It suits sites with original, brand-safe content and some traffic history. It's now part of Improve Digital, which Azerion owns.
+PubGalaxy was an ad revenue service that reviewed each publisher one by one. In September 2026, its owner Azerion moved it under the Improve Digital name, and pubgalaxy.com now opens Improve Digital's site. Its current joining rules and pay terms aren't public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/joining.mdx
index 2f1bb724..aef9c4d7 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/joining.mdx
@@ -1,5 +1 @@
-## Who can join PubGalaxy?
-
-PubGalaxy has no hard entry rules. It suggests a traffic level but reviews each site on its own. It asks for six months of traffic history and checks the Google Transparency Report for copyright claims against your site.
-
-Content should be original and brand safe. Stolen or automated content isn't allowed, and neither are violence, nudity, gambling, or banned substances. Apply through its publisher contact page.
+PubGalaxy's old joining rules may not apply since its move to Improve Digital, and Improve Digital's pages don't list rules for new publishers. Ask Improve Digital about traffic and content rules before you apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/pay.mdx
index da1b561d..8ae009ec 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/pay.mdx
@@ -1,5 +1,3 @@
## How does PubGalaxy pay?
-The published terms give you at least 85% of net revenue from ad partners and at least 65% from direct deals. PubGalaxy pays within 35 days after the month ends, once it receives the advertiser's money.
-
-The currency is not public.
+Not public. PubGalaxy's old pay terms may not apply since its move to Improve Digital, and Improve Digital's pages don't confirm them for new publishers. Ask Improve Digital for the share, pay day, and payment minimum you'd get.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/rules.mdx
index 4f8fdfba..c1cd8f78 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/rules.mdx
@@ -1,5 +1,3 @@
## What rules does PubGalaxy set?
-You must own or license your content and let PubGalaxy manage your ad inventory. It can make changes that improve the reader experience, and the terms set rules for direct deals.
-
-PubGalaxy says terms can vary by publisher. Check exclusivity and notice in the order you sign.
+PubGalaxy's old terms had you own or license your content and let it manage your ad inventory. Since the move to Improve Digital, the current rules aren't public. Check exclusivity and notice in the order you sign.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/service.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/service.mdx
index d817d4ae..01225cfc 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/service.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubgalaxy/service.mdx
@@ -1,3 +1,3 @@
## What does PubGalaxy do for you?
-You get detailed earnings reports and access to direct and private marketplace deals. Support response times are not public.
+PubGalaxy offered detailed earnings reports and access to direct and private marketplace deals. Ask Improve Digital what new publishers get now. Support response times are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publift/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publift/article.mdx
index 839b8581..55a87e6b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publift/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publift/article.mdx
@@ -1,11 +1,23 @@
+## Who is Publift a fit for?
+
+Sites that already earn steadily from ads. Publift works best when most readers are in the Americas, Europe, or Australia and New Zealand, though it doesn't call that a hard cutoff. Your traffic should be steady and genuine, and your content useful and safe.
+
## Does Publift care more about revenue or traffic?
Revenue. Publift uses monthly ad revenue as its main test and treats pageviews as a hint. A site with fewer pageviews but strong earnings can still fit.
-## When does Publift pay?
+## What should you have ready before you apply?
+
+Your recent monthly ad earnings and traffic numbers. Since revenue comes first, have your earnings reports ready to show.
+
+## What should you confirm in your order?
+
+Your share, whether the service is month to month, and any exclusivity or layout rules. Publift's 2026 comparison describes an 80/20 split and month-to-month service, but the requirements page doesn't, so get both in writing.
+
+## Where else can a global site go?
-It depends on where the money comes from. Google revenue is paid sooner than revenue from other networks. Check the dates in your order.
+[Clickio](/ad-networks/clickio) sets its traffic bar by visitor region. [Google AdSense](/ad-networks/google-adsense) has no traffic minimum.
## How can you check if a site uses Publift?
-Look for Publift in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Publift.
+Look for Publift in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publift/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publift/joining.mdx
index 9ca68383..df882f92 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publift/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publift/joining.mdx
@@ -1,5 +1,5 @@
-## Who can join Publift?
-
Publift looks at your monthly ad revenue first. Pageviews are a secondary signal, not a strict rule. Your traffic should be steady and genuine, and your content useful and safe.
-You apply for a site review. Publift doesn't say which regions it accepts.
+Publift works best when most of your readers are in the Americas, Europe, or Australia and New Zealand. It doesn't call that a strict cutoff.
+
+You apply for a site review. Publift gives a time for sending your ad tags, but it doesn't say how much of that is the review itself.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publift/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publift/pay.mdx
index a3510725..b285d94a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publift/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publift/pay.mdx
@@ -2,4 +2,4 @@
Publift's comparison page lists payment by direct bank transfer, with Google revenue on Net 30 and other network revenue on Net 90. That page is marketing content, so confirm the currency and terms in your order.
-The share is not on its requirements page.
+Publift's 2026 comparison also describes the revenue split. It isn't on the requirements page, so confirm it in your order.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publir/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publir/article.mdx
index 5a8b165e..3cc94f34 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publir/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publir/article.mdx
@@ -1,15 +1,23 @@
+## Who is Publir a fit for?
+
+Sites of any size, since it has no traffic or revenue minimum. It suits publishers who want more than ad slots, such as ad block recovery, subscriptions, or crowdfunding.
+
## Which Publir model fits you?
Pro suits a site that wants Publir to run its ads for a fee. Custom ad deals under the service agreement work on a revenue split instead. Ask which model you'd be on before you sign.
## Can Publir change its fees?
-Yes. The service agreement allows Publir to change its percentages for costs and fees.
+Yes. The service agreement allows Publir to change its percentages for costs and fees. Ask how you'd be told about a change.
+
+## How long does it take to start?
+
+The service agreement says onboarding may take ten business days. Plan your switch around that.
-## What else does Publir offer besides ads?
+## What should you ask before you sign?
-Ad block recovery, subscriptions, crowdfunding, and QuickShop. These can add income beyond ad slots.
+The payment minimum and how you're paid. Neither is public.
## How can you check if a site uses Publir?
-Look for Publir in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Publir.
+Look for Publir in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publir/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publir/intro.mdx
index e586edae..8a571ac5 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publir/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publir/intro.mdx
@@ -1 +1 @@
-Publir is an ad optimization and audience monetization platform. It has no traffic or revenue minimum, so sites of any size can try it.
+Publir is an ad optimization and audience monetization platform. Its service agreement is non-exclusive, so you can keep your other ad partners.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publir/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publir/joining.mdx
index ca23e7c7..b2ef1519 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publir/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publir/joining.mdx
@@ -1,3 +1 @@
-## Who can join Publir?
-
Publir has no traffic or revenue limit. It offers Pro and Enterprise plans, and you apply from its pricing page. Location and content rules are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publir/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publir/pay.mdx
index 1f658dc2..f305f68a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publir/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publir/pay.mdx
@@ -1,5 +1,7 @@
## How does Publir pay?
-Publir has two models. Its Pro service charges a 15% fee. Under its service agreement, custom ad revenue is split 50/50 and paid on Net 60. There's no single share for every publisher.
+What you keep depends on the service. Pro charges a fee. Under the service agreement, you keep most of your programmatic and subscription revenue, custom ad revenue is split evenly, and Publir takes a fee on crowdfunding. There's no single share for every publisher.
+
+Programmatic and custom ad earnings are paid at least monthly, on Net 60. Subscription revenue is paid at least monthly.
The payment minimum, methods, and currency are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publir/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publir/rules.mdx
index 9db87427..9686e997 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publir/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publir/rules.mdx
@@ -1,3 +1,3 @@
## What rules does Publir set?
-The service agreement lets Publir change its percentages to cover costs and fees. Exclusivity, content rules, contract length, and notice are not public.
+The service agreement is non-exclusive, and either side can end it with notice. It also lets Publir change its percentages to cover costs and fees. Content rules and contract length are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/article.mdx
index 17848d97..9f828b19 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/article.mdx
@@ -1,15 +1,23 @@
+## Who is Publisher Collective a fit for?
+
+Sites that want a team to sell their ads and are happy to hand over the ad tags. Publisher Collective looks for about €300 a day in ad revenue, and 3 million pageviews a month for sites outside its main topics. It may still take a smaller site that's growing fast or high quality. You must own or have rights to your content.
+
+## What happened to Snigel?
+
+Snigel and Publisher Collective merged in February 2025. Publisher Collective now sells under its own name and keeps Snigel as its ad technology. Many sites still name Snigel's domain, snigelweb.com, in their ads.txt files. We count those sites under Publisher Collective.
+
## When does Publisher Collective pay you?
-After the advertiser pays Publisher Collective. The partner terms don't set a fixed interval, so ask how long that usually takes.
+After the advertiser pays Publisher Collective. The partner terms don't set a fixed interval, so ask how long that usually takes. The €500 minimum is high, so a small site may wait several months for a first payment.
## What do you give up with Publisher Collective?
You can't edit its ad tags, and you may need to send advertiser leads its way. Read those terms closely if you also sell ads directly.
-## What happened to Snigel?
+## What do you need to keep up with after you join?
-Snigel and Publisher Collective merged in February 2025. Publisher Collective now sells under its own name and keeps Snigel as its ad technology. Many sites still name Snigel's domain, snigelweb.com, in their ads.txt files. We count those sites under Publisher Collective.
+Replies to Publisher Collective. You may need to update site materials within seven days, and the deal can be suspended or ended if you don't respond.
## How can you check if a site uses Publisher Collective?
-Look for Publisher Collective or Snigel in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Publisher Collective.
+Look for Publisher Collective or Snigel in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/joining.mdx
index 979560f7..1ec4770b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/publisher-collective/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Publisher Collective?
+The revenue and pageview bars aren't hard floors. Publisher Collective may still take a smaller site that's growing fast or has high-quality content.
-There's no published traffic minimum. You must own or have rights to your content and follow its terms. Apply through its publisher contact page, then sign an Advertising Representation Agreement.
-
-Regions aren't fixed in the public terms.
+You must own or have rights to your content, bring real traffic with no bots, and follow its terms. Apply through its publisher contact page, then sign an Advertising Representation Agreement. Once you're in, you add its JavaScript tags to your site.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/article.mdx
index 877ede9b..99811257 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/article.mdx
@@ -4,8 +4,12 @@ PubNation doesn't publish how to apply. Contact the company through its website.
## What should you ask PubNation before you sign?
-Ask for the share, when you'd be paid, the payment minimum, and whether it must be your only ad partner. Ask how much notice you'd need to leave.
+Ask for the share, when you'd be paid, the payment minimum, and whether it must be your only ad partner. Ask how much notice you'd need to leave, and who decides where ads go.
+
+## What if you want public terms first?
+
+[Raptive](/ad-networks/raptive) and [Mediavine](/ad-networks/mediavine) publish their entry rules, share, and pay day. [Journey by Mediavine](/ad-networks/journey-by-mediavine) publishes a low traffic bar for growing sites.
## How can you check if a site uses PubNation?
-Look for PubNation in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to PubNation.
+Look for PubNation in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/joining.mdx
index 4f8f096e..59697a1e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubnation/joining.mdx
@@ -1,3 +1 @@
-## Who can join PubNation?
-
-Not public. PubNation doesn't publish a traffic minimum, site rules, accepted regions, or how to apply.
+PubNation says it works with top-earning publishers, but it doesn't publish a traffic minimum, site rules, accepted regions, or how to apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/article.mdx
index 81d3221a..1ef2419e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/article.mdx
@@ -1,11 +1,19 @@
+## Who is PubPower a fit for?
+
+Publishers who want fast payment. Sites that earn more than $3,000 a month are paid on Net 0, in the payment window early the next month. PubPower looks for around 100,000 visitors a month, and its review usually takes a few days.
+
## Why do some PubPower sites get paid sooner?
-PubPower pays sites above its monthly revenue line as soon as the month ends, with no waiting period. Other sites wait for the standard term.
+PubPower pays sites above its monthly revenue line on Net 0, in its payment window from the 1st to the 20th of the next month. Other sites wait for the standard Net 30 term, which is still quicker than many managed networks.
## Which PubPower payment method should you pick?
-Pick one with a minimum your earnings clear. Payoneer has the lowest minimum, and bank transfer the highest.
+Pick one with a minimum your earnings clear. Payoneer has the lowest minimum, and bank transfer the highest. A small site on bank transfer could wait months for a payment.
+
+## What should you ask before you sign?
+
+Your exact share, the payout currency, and whether PubPower must be your only ad partner. Ask how much notice you need to leave. None of these are public.
## How can you check if a site uses PubPower?
-Look for PubPower in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to PubPower.
+Look for PubPower in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/joining.mdx
index 9495dcc1..135994e0 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/joining.mdx
@@ -1,3 +1,5 @@
-## Who can join PubPower?
+PubPower's traffic guideline is approximate, not a strict cutoff. It doesn't publish which regions it accepts.
-Not public. PubPower doesn't publish a traffic minimum, content rules, accepted regions, or how to apply.
+Your site must follow PubPower's content policy, which bars or restricts sexual, explicit, violent, illegal, gambling, and infringing content. Pop-ups and redirects aren't allowed.
+
+To start, you add PubPower's ads.txt lines and install its ad tag. Its quick-start guide and FAQ give different review times, and weekends can take longer.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/pay.mdx
index 81f92e0b..871e3ef2 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/pay.mdx
@@ -2,4 +2,4 @@
If you earn more than $3,000 in a month, PubPower pays on Net 0. Otherwise it pays on Net 30.
-The minimum depends on the method: $50 for Payoneer, $100 for PayPal, $100 to $1,000 for crypto, and $1,000 for a bank transfer. The share and payout currency are not public.
+The minimum depends on the method: $50 for Payoneer, $100 for PayPal, $100 to $1,000 for crypto, and $1,000 for a bank transfer. On the Essential package, your share is set for you and not published. On Advanced, bidders you bring yourself carry no revenue share. The payout currency is not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/rules.mdx
index 909a51e4..62e915c2 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/pubpower/rules.mdx
@@ -1,5 +1,5 @@
## What rules does PubPower set?
-Not public. Exclusivity, placement control, content rules, contract length, and notice aren't on its payment page.
+PubPower's content policy bars or restricts sexual, explicit, violent, illegal, gambling, and infringing content, and it doesn't allow pop-ups or redirects. Exclusivity, placement control, contract length, and notice are not public.
A revenue share article on its help site is for ad networks using its white-label product, not for publishers.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/article.mdx
index de28bd94..196625a1 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/article.mdx
@@ -1,11 +1,23 @@
-## Is Raptive a fit for your site?
+## Who is Raptive a fit for?
-It is if you write original content and most of your readers are in the US, Canada, UK, Australia, or New Zealand. Sites with most traffic elsewhere won't qualify.
+Sites with original, human-led content and a large share of readers in the US, Canada, UK, Australia, or New Zealand. Below 100,000 monthly pageviews, at least half your traffic must come from those countries. Above that, the bar is 40%.
-## Does your Raptive service change as you grow?
+## What should you have ready before you apply?
-Yes. A dedicated manager, custom layouts, and fuller reporting depend on your tier.
+Google Analytics set up on your site, since Raptive asks for it. Check there that you're above the pageview bar and that enough visitors come from its five countries for your traffic tier. Your domain must also be at least six months old. Raptive doesn't publish how long review takes.
+
+## How does Raptive's pay compare with Mediavine?
+
+Raptive publishes a 75% share. [Mediavine](/ad-networks/mediavine)'s ranges from 75% to 90%, depending on its program tier. Raptive pays on Net 45, sooner than Mediavine's Net 65, and its minimum is $25 for most methods. Mediavine sets a yearly ad revenue bar instead of a pageview bar.
+
+## What should you ask before you sign?
+
+Whether Raptive must be your only ad partner, how long the contract runs, and how much notice you need to leave. Ask what placement controls you keep. None of these are public.
+
+## What if your site doesn't qualify yet?
+
+[Journey by Mediavine](/ad-networks/journey-by-mediavine) starts at 1,000 premium sessions a month. [Monumetric](/ad-networks/monumetric)'s Propel program has a lower pageview bar, with a similar reader location rule. If too few readers are in Raptive's countries, [Clickio](/ad-networks/clickio) sets its bar by region, and [Google AdSense](/ad-networks/google-adsense) has no traffic minimum.
## How can you check if a site uses Raptive?
-Look for Raptive in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Raptive.
+Look for Raptive in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/intro.mdx
index 9c624913..5ad5635b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/intro.mdx
@@ -1 +1 @@
-Raptive is a managed ad service for creators and independent publishers. It suits established sites with most readers in the US, Canada, UK, Australia, or New Zealand.
+Raptive is a managed ad service for creators and independent publishers. It suits established sites with a large share of readers in the US, Canada, UK, Australia, or New Zealand.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/joining.mdx
index a7dbf63c..5b9ec112 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/raptive/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/raptive/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Raptive?
-
-Most of your traffic must come from the US, Canada, UK, Australia, or New Zealand. You need original content and Google Analytics set up.
+A set share of your traffic must come from the US, Canada, UK, Australia, or New Zealand. That share drops once your site passes a higher traffic tier. You need original, human-led content, a domain that meets Raptive's minimum age, and Google Analytics access.
Apply through Raptive's creator application.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/article.mdx
index d4bfc998..6b36d7cd 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/article.mdx
@@ -1,11 +1,19 @@
+## Who is Refinery89 for?
+
+Publishers who want one named contact for their ads. Each publisher works with a Publisher Success Manager. Refinery89 works with publishers worldwide but doesn't publish other entry rules, so contact its publisher team.
+
## When does Refinery89 pay?
-It depends on your terms. Refinery89 has more than one payment schedule, so ask your Publisher Success Manager which one is yours.
+It depends on your terms. Refinery89 doesn't publish a standard schedule, so ask your Publisher Success Manager which one is yours. The minimum is €250 or $250 a month, so a small site may carry a balance for a while.
## What can you see in the Refinery89 dashboard?
Daily revenue, CPM, RPM, pageviews, fill rate, and viewability, plus invoices and support tickets. You can export your data and manage ads.txt there too.
+## What should you ask before you sign?
+
+Your share, your payment schedule, and whether Refinery89 must be your only ad partner. Ask how long the contract runs and how much notice you need to leave.
+
## How can you check if a site uses Refinery89?
-Look for Refinery89 in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Refinery89.
+Look for Refinery89 in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/joining.mdx
index 4c32720d..1b11480e 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/joining.mdx
@@ -1,3 +1 @@
-## Who can join Refinery89?
-
-Not public. Refinery89 doesn't publish a traffic minimum, site rules, eligible regions, or how to apply. Contact its publisher team.
+Refinery89 doesn't publish a traffic minimum or site rules. Contact its publisher team to start. Once you're set up, you add its tag to your site or its SDK to your app.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/pay.mdx
index 542691d3..27c0088a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/refinery89/pay.mdx
@@ -1,5 +1,5 @@
## How does Refinery89 pay?
-The payment minimum depends on your region. Refinery89 publishes more than one set of payment terms, so ask your Publisher Success Manager for your schedule.
+The payment minimum and currency depend on your region. There's no standard payment schedule, so ask your Publisher Success Manager for yours.
-The share, methods, and currency are not fully public.
+The share is not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/article.mdx
index 15782d57..4af395bc 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/article.mdx
@@ -1,3 +1,7 @@
+## Who is Revcontent a fit for?
+
+Sites that want content recommendation widgets and native ads. Revcontent has no traffic minimum and no published region rule, but your site must follow its publisher terms and content policy.
+
## How is your Revcontent share set?
You negotiate it. Revcontent doesn't publish a standard rate, so compare its offer with what you earn now.
@@ -6,6 +10,14 @@ You negotiate it. Revcontent doesn't publish a standard rate, so compare its off
It depends. The terms set one floor, and each payment method sets its own. Check your dashboard or order for the one that applies to you.
+## Which payment method should you pick?
+
+In the US, ACH has the lowest minimum. Outside the US, PayPal's minimum is far lower than an international wire.
+
+## How does Revcontent compare with Taboola and MGID?
+
+[Taboola](/ad-networks/taboola) must be your only recommendation service while your deal runs. [MGID](/ad-networks/mgid) publishes a regional offer with a share and pay day. Revcontent negotiates each deal.
+
## How can you check if a site uses Revcontent?
-Look for Revcontent in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Revcontent.
+Look for Revcontent in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/joining.mdx
index f6e0c9b3..2d5de7aa 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/revcontent/joining.mdx
@@ -1,3 +1 @@
-## Who can join Revcontent?
-
-Revcontent doesn't publish a traffic minimum or region rule. You apply for approval, and your site must follow its publisher terms and content rules.
+Revcontent has no traffic minimum and no published region rule. You apply for approval, and your site must follow its publisher terms and content rules.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/article.mdx
index 406d9fb2..32cc8945 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/article.mdx
@@ -1,11 +1,27 @@
+## Who is Setupad a fit for?
+
+Publishers who want a platform to run their display ads. Its 2025 publisher guide looks for about 100,000 monthly visitors, mostly from the US, UK, Canada, and Australia. Self-Serve, its newer product, has separate plans for sites with 10 million or more monthly visits.
+
## Why are Setupad's rules unclear?
-Setupad's published rules are in blog articles from different years, and they don't fully agree. Ask its team for current eligibility before you count on them.
+Setupad's guidance doesn't fully agree with itself. The 2025 guide counts visitors in one place and sessions in another, and Self-Serve has its own plans. Ask its team for current eligibility before you count on them.
+
+## What should you have ready before you apply?
+
+An ads.txt file you can update, and a site that meets Setupad's quality policy. Setupad doesn't accept low-quality sites.
## How can Setupad pay you?
By bank transfer, PayPal, Payoneer, Wise, Revolut, or Paysera, according to its guidance.
+## How much does Setupad take?
+
+It depends on where the money comes from. If you use Setupad's optional reseller demand, Setupad keeps 20%. On Self-Serve, demand partners you work with directly pay you under their own agreements, and Setupad charges a flat €0.05 per thousand impressions.
+
+## What should you ask before you sign?
+
+The currency you're paid in, and whether Setupad must be your only ad partner. Ask how long the contract runs and how much notice you need to leave.
+
## How can you check if a site uses Setupad?
-Look for Setupad in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Setupad.
+Look for Setupad in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/joining.mdx
index 20436579..a0269188 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/joining.mdx
@@ -1,5 +1,3 @@
-## Who can join Setupad?
+Setupad's 2025 publisher guide gives a traffic guideline, but it counts visitors in one section and sessions in another. Most of your traffic should come from the US, UK, Canada, or Australia. Self-Serve, its newer product, has its own plans for much larger sites, so check which one you're applying for.
-Setupad's articles from different years describe a traffic rule, but one counts visitors and another counts sessions. They also mention traffic from the US, UK, Canada, and Australia. We didn't find a current criteria page, so confirm with Setupad.
-
-You need to follow ad policies and set up ads.txt. Apply through Setupad's publisher contact page.
+Your site must meet Setupad's quality policy, and low-quality sites aren't accepted. You set up ads.txt and run Setupad's demand sources, including Google. Apply through Setupad's publisher contact page.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/pay.mdx
index e6e1df99..23b83f64 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/setupad/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/setupad/pay.mdx
@@ -1,3 +1,5 @@
## How does Setupad pay?
-Setupad's published guidance lists Net 60 payment. The share and currency are not public.
+Setupad's published guidance sets the payment timing and minimum for its managed service and its optional reseller demand. On Self-Serve, demand partners you work with directly pay you under their own agreements. For that demand, Setupad charges a flat fee per thousand impressions instead of a share.
+
+The currency is not public, and neither is the minimum for reseller demand on Self-Serve.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/article.mdx
index e62919ed..6ff86e1f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/article.mdx
@@ -1,11 +1,19 @@
## How do you join SHE Media?
-SHE Media doesn't publish a general application checklist. Its referral program lists criteria for referred sites, which is the clearest public guide.
+Apply online and give SHE Media access to your Google Analytics. It typically looks for 50,000+ monthly pageviews and at least 30% US traffic, though it may consider smaller sites case by case. Expect a reply in three to four weeks.
+
+## What does SHE Media look for?
+
+Original, brand-safe, human-led content on a site that's at least 90 days old. You also need a good track record with Google's ad products. If you use AI-generated images, label them clearly.
## Can publishers outside the US work with SHE Media?
-Yes. SHE Media has payment options for publishers outside the US, including PayPal, Wise, ACH, and wire. Payoneer isn't one of them.
+Yes, but check how you'll be paid. Its FAQ says international publishers must use PayPal, and it can't work with countries where PayPal isn't available. A 2025 support guide adds Wise, ACH, and wire, if approved. Payoneer isn't one of them, so ask which method you'll get before you join.
+
+## What should you ask before you sign?
+
+Whether the 75% share and $20 minimum in its 2023 Member Guide still apply to you, and when your 12-month contract renews, since you must give 60 days' notice to stop it. SHE Media must be your only banner ad partner, so check which other ads you can keep.
## How can you check if a site uses SHE Media?
-Look for SHE Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to SHE Media.
+Look for SHE Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/intro.mdx
index baf495ba..a3446220 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/intro.mdx
@@ -1 +1 @@
-SHE Media runs a partner network for publishers. Its joining rules and pay share are not public.
+SHE Media runs a partner network for publishers with original, brand-safe content. It wants at least 30% of traffic from the US, and may consider smaller sites case by case.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/joining.mdx
index 1a1154bd..d3425787 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/joining.mdx
@@ -1,5 +1,5 @@
-## Who can join SHE Media?
+SHE Media usually wants a set monthly traffic level, but it may consider smaller sites case by case. It also wants a solid share of US readers, a site that's been live for a while, and a good track record with Google's ad products.
-SHE Media doesn't publish a general traffic minimum. Its referral program mentions a traffic level for referred sites, along with quality content and Google Analytics. That's for referrals, not every applicant.
+Your content must be original, brand-safe, and human-led. If you use AI-generated images, add a clear disclaimer.
-Regions and a current checklist are not public.
+Apply online and share your Google Analytics. Onboarding includes Google MCM and an ads.txt file. The team aims to reply within a few weeks, but a reply isn't a final decision.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/pay.mdx
index c2e88161..2ad7a9d4 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/pay.mdx
@@ -1,5 +1,5 @@
## How does SHE Media pay?
-The share, payment schedule, and general minimum are not public.
+SHE Media pays after each month closes. Its share and payment minimum come from its Member Guide, last updated in March 2023, so check both against your contract.
-Outside the US, SHE Media pays by PayPal if you earn under $1,000 a month, and prefers wire transfer above that. Wise and ACH are options too. Payoneer isn't accepted. Currency is not public.
+US publishers are paid by direct deposit, or by check if ACH isn't available. Outside the US, SHE Media's pages disagree. Its FAQ says you must use PayPal, and it can't work with countries where PayPal isn't available. An April 2025 support guide says PayPal if you earn under $1,000 a month, with wire preferred above that, and Wise or ACH if approved. Payoneer isn't accepted. Currency is not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/rules.mdx
index f9b16605..f6f622bd 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/she-media/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/she-media/rules.mdx
@@ -1,3 +1,5 @@
## What rules does SHE Media set?
-Not public. Exclusivity, ad placement control, content rules, contract length, and notice aren't on its publisher help pages.
+SHE Media must be your only partner for mobile and desktop banner ads. Affiliate links and affiliate banners are allowed alongside it. Its support team works with you on an ad layout you're happy with.
+
+Contracts run for 12 months and renew on their own. To stop the renewal, tell SHE Media at least 60 days before it. Leave the ad code in place until the end date SHE Media gives you. Its FAQ doesn't say how much notice SHE Media must give you.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/article.mdx
index f85a9959..b6b8dfe6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/article.mdx
@@ -1,11 +1,23 @@
+## What should you have ready before you join Snack Media?
+
+Live traffic stats to share, and time to add its ad tags. The tags must be live within 14 days of signing.
+
## Can you leave Snack Media?
-Yes. Either side can end the contract with notice, and after the first term it runs month to month.
+Yes. Either side can end the contract with 30 days' notice, and after the first term it runs month to month.
## Does Snack Media need to be your only ad partner?
Only if your order says so. Check the cover sheet before you sign.
+## When does Snack Media pay?
+
+Within 30 days after the month it receives the advertiser's money. So your pay depends on when advertisers pay Snack Media, not only on when you earned it.
+
+## What should you check on the cover sheet?
+
+Your share, the length of the first term, and any exclusivity. The standard terms leave all three to the cover sheet.
+
## How can you check if a site uses Snack Media?
-Look for Snack Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Snack Media.
+Look for Snack Media in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/joining.mdx
index b099580d..228964ec 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/snack-media/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Snack Media?
+Snack Media's standard agreement sets no traffic minimum. Its referral program has its own traffic bar, asks you to follow Google's policies, and leaves out sensitive and gambling sites.
-Not public. Snack Media doesn't publish a traffic minimum, content rules, regions, or an application process. Contact it through its site.
+Every site must avoid hateful, pornographic, illegal, or infringing content. Accepted regions aren't public. Contact Snack Media through its site.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/article.mdx
index 0245d4ec..ee645088 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/article.mdx
@@ -1,11 +1,23 @@
+## Is Sovrn a fit for a small site?
+
+Not for the Ad Exchange. It asks for more than 100,000 visits a month. Once you're in, its $25 payment minimum is lower than [Google AdSense](/ad-networks/google-adsense)'s $100.
+
+## What should you have ready before you apply?
+
+A working domain, an ad system ID, and an ads.txt file you keep up to date. Sovrn's approval guide also checks that your content is current and brand safe.
+
## What's the difference between Sovrn's Ad Exchange and Sovrn Commerce?
The Ad Exchange sells ad space on your site. Sovrn Commerce is a separate affiliate product with its own payment terms. The details on this page are for the Ad Exchange.
-## Is Sovrn a fit for a small site?
+## How does Sovrn pay?
+
+On Net 45, in US dollars, with some options to get local currency. Pick a method other than wire if you want the lowest minimum.
+
+## What should you ask before you sign?
-It can be. The Ad Exchange doesn't set a traffic minimum, and its payment minimum is low.
+Your share, and whether there's an exclusivity rule or contract length. Neither is on the approval or payment pages.
## How can you check if a site uses Sovrn?
-Look for Sovrn in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Sovrn.
+Look for Sovrn in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/intro.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/intro.mdx
index 5498d669..1ed1603f 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/intro.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/intro.mdx
@@ -1 +1 @@
-Sovrn offers an ad exchange and other monetization tools for publishers. Its Ad Exchange has no published traffic minimum.
+Sovrn offers an ad exchange and other monetization tools for publishers. This page covers its Ad Exchange.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/joining.mdx
index 3285008a..2fabcc76 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Sovrn?
+Sovrn checks that your content is current and brand safe, and that you own the site. You need a working business domain and an ad system ID, and you must keep your ads.txt file up to date. Resellers also need a sellers.json file.
-You need a working business domain and an ad system ID, and you must keep your ads.txt file up to date. Sovrn's approval guide doesn't set a traffic minimum.
+How long approval takes depends on outside checks and whether your site needs a manual review.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/rules.mdx
index cbfadc0b..7ee66912 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sovrn/rules.mdx
@@ -1,3 +1,3 @@
## What rules does Sovrn set?
-The Ad Exchange approval and payment pages don't state exclusivity, placement control, content rules, contract length, or notice. Sovrn Commerce has its own terms.
+The Ad Exchange approval and payment pages don't state exclusivity, placement control, contract length, or notice. Sovrn Commerce has its own terms.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/article.mdx
index a9b9931d..d62a0978 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/article.mdx
@@ -2,10 +2,18 @@
Video through Viously, consent management through FastCMP, and Actirise, plus analytics on revenue and page speed.
+## Who is Sparteo a fit for?
+
+Publishers who want ads, video, and consent tools from one company, with reports that include Core Web Vitals. Sparteo doesn't publish who qualifies.
+
## How do you work with Sparteo?
Sparteo doesn't publish how to apply. Contact the company to ask.
+## What should you ask before you sign?
+
+Your share, when you're paid, the payment minimum, and how you're paid. Ask whether Sparteo must be your only ad partner and how much notice you need to leave. None of this is public.
+
## How can you check if a site uses Sparteo?
-Look for Sparteo in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Sparteo.
+Look for Sparteo in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/joining.mdx
index 0760291b..4d896500 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/sparteo/joining.mdx
@@ -1,3 +1 @@
-## Who can join Sparteo?
-
-Not public. Sparteo doesn't publish a traffic minimum, site rules, regions, or how to apply.
+Sparteo doesn't publish a traffic minimum, site rules, regions, or how to apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/article.mdx
index 064cf4ad..88f316b5 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/article.mdx
@@ -1,11 +1,23 @@
+## Who is Taboola a fit for?
+
+Sites that want recommended stories and ads under or beside their content. Taboola doesn't publish a traffic minimum, but your site must follow its Publisher Policy.
+
## Can you run Taboola with another recommendation widget?
No. Taboola must be your only recommendation service during the agreement. The rule covers recommendation services, so check your order for anything else.
-## What content can't run Taboola?
+## How does Taboola pay?
+
+In US dollars, within 45 days after the month ends. Most publishers are paid through Payoneer, but the options depend on where you are, so check yours when you set up your account.
+
+## What should you check in your order?
+
+Your share, the contract length, and how to end it. Taboola's order sets all three, and they aren't public.
+
+## What else runs recommendation ads?
-Fake news, porn, copyright violations, defamation, threats, and criminal material are banned under its Publisher Policy.
+[Revcontent](/ad-networks/revcontent) and [MGID](/ad-networks/mgid) both run native and recommendation ads. Because of Taboola's exclusivity rule, you'd pick Taboola or one of them, not both.
## How can you check if a site uses Taboola?
-Look for Taboola in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Taboola.
+Look for Taboola in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/joining.mdx
index dbed98c7..f6524497 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Taboola?
+Taboola doesn't publish a traffic minimum or region rule. You need to own or properly license your content, and your site must follow the Taboola Publisher Policy.
-Taboola doesn't publish a traffic minimum or region rule. Your site must follow the Taboola Publisher Policy. Apply by contacting Taboola.
+Apply through Taboola's online form. Its team replies quickly, but a reply isn't final approval. Once you're in, you add Taboola's widget code to your pages.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/pay.mdx
index c3f48c6c..e5f94d24 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/taboola/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/taboola/pay.mdx
@@ -1,3 +1,3 @@
## How does Taboola pay?
-Your share is set in your order. Taboola pays in US dollars within 45 days after the month ends, through Payoneer. A general payment minimum is not public.
+Your share is set in your order. Taboola pays in US dollars within 45 days after the month ends. Most publishers are paid through Payoneer, and other options depend on where you are. A general payment minimum is not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/teads/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/teads/article.mdx
index 09b8a416..445beec6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/teads/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/teads/article.mdx
@@ -1,3 +1,7 @@
+## Who is Teads a fit for?
+
+Publishers with web, connected TV, or app inventory who want premium ad placements. Teads also offers content extension. It doesn't publish entry rules.
+
## Is Teads the same as Outbrain?
Teads now includes what used to be Outbrain's business.
@@ -6,6 +10,14 @@ Teads now includes what used to be Outbrain's business.
Teads doesn't publish an application process. Its media owner page is where to start a partnership conversation.
+## When does Teads pay?
+
+Your contract sets it. Teads doesn't publish a standard payment term for publishers, so get yours in writing.
+
+## What should you ask before you sign?
+
+Your share, the payment minimum, and whether Teads must be your only ad partner. Ask how long the contract runs and how much notice you need to leave.
+
## How can you check if a site uses Teads?
-Look for Teads in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Teads.
+Look for Teads in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/teads/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/teads/joining.mdx
index 9631c698..09085523 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/teads/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/teads/joining.mdx
@@ -1,3 +1 @@
-## Who can join Teads?
-
-Not public. Teads describes partnerships across web, CTV, and apps, but doesn't publish a traffic minimum, content rules, regions, or how to apply.
+Teads describes partnerships across web, CTV, and apps, but doesn't publish a traffic minimum, content rules, regions, or how to apply.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/teads/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/teads/pay.mdx
index 87273b6c..3fff299b 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/teads/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/teads/pay.mdx
@@ -1,5 +1,5 @@
## How does Teads pay?
-Your share is set in your contract. A Teads company filing says publisher payment terms usually run 30 to 60 days, but that's not one fixed term.
+Your share is set in your contract, and the rate can change with your pageviews or total revenue. Payment timing is negotiated in the contract too, with no standard term.
The payment minimum, methods, and currency are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/article.mdx
index e3366bfc..5e5b96bb 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/article.mdx
@@ -1,11 +1,19 @@
+## Who is The Moneytizer a fit for?
+
+Publishers who want a managed header bidding service with a low payment minimum of €50 or $50. That suits a small site that would wait months to reach a $100 minimum.
+
## When does The Moneytizer pay you?
-A couple of months after the month you earn it. The payment simulator on its site shows how the timing works.
+About two months after your invoice. The Moneytizer creates the invoice once your earnings reach the minimum. The payment simulator on its site shows how the timing works.
## How do you join The Moneytizer?
-Sign up on its site. The Moneytizer doesn't publish entry rules, so its team decides.
+Sign up on its site and share your traffic stats. The Moneytizer doesn't publish a traffic minimum. Its team reviews each site for advertiser fit and content.
+
+## What should you ask before you sign?
+
+How long The Moneytizer can take to end your account, since its terms give it no notice period. You don't have to make it your only ad partner, and you must give 30 days' notice to leave.
## How can you check if a site uses The Moneytizer?
-Look for The Moneytizer in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to The Moneytizer.
+Look for The Moneytizer in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/joining.mdx
index 78382207..c6778a9d 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join The Moneytizer?
+You sign up on The Moneytizer's site and share your traffic stats. It doesn't publish a traffic minimum. Its team reviews each site for advertiser fit, and it doesn't say how long that takes.
-Not public. The Moneytizer doesn't publish a traffic minimum, content rules, regions, or application steps. Its site has a publisher sign-up page.
+Once you're in, you add its ads.txt lines and ad tags. Sites with EU visitors also need a consent banner.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/pay.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/pay.mdx
index cc37f93c..46634fbc 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/pay.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/pay.mdx
@@ -1,3 +1,3 @@
## How does The Moneytizer pay?
-After each month ends, The Moneytizer creates your invoice, and payment follows about two months later. The payment method and share are not public.
+The Moneytizer creates your invoice once your earnings reach the minimum, and pays it about two months later. It pays by bank transfer or PayPal. The terms set your share as a minimum, so you may get more.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/rules.mdx
index 7f436511..35c552f6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/the-moneytizer/rules.mdx
@@ -1,3 +1,5 @@
## What rules does The Moneytizer set?
-Not public. Exclusivity, placement control, content rules, contract length, and notice aren't in its payment information.
+The Moneytizer doesn't need to be your only ad partner. Its terms bar content that is racist, xenophobic, pedophilic, against human dignity, or illegal. You can remove its tags at any time if they clash with your editorial policy, and you choose which ad formats appear.
+
+The terms set no fixed contract length. If you joined after March 11, 2024, you must give 30 days' notice to leave, or your last period's earnings may not be paid as agreed. The Moneytizer can close your account at any time if it earns $5 a month or less, or remove it if you break the terms. Its terms give no notice period for either.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/article.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/article.mdx
index fa4301a4..4db5f164 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/article.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/article.mdx
@@ -4,8 +4,12 @@ Publishers in gaming, sports, and entertainment. If your site covers those topic
## How do you apply to Venatus?
-Fill in the publisher interest form on its site. Venatus doesn't publish entry rules, so its team decides.
+Fill in the publisher interest form on its site. A person on its team audits your site against its content rules. Venatus doesn't publish a traffic or region bar, so its team decides the rest.
+
+## What should you ask before you sign?
+
+Your share, when you're paid, and the payment minimum. Ask whether Venatus must be your only ad partner, who decides where ads go, and how much notice you need to leave. None of this is public.
## How can you check if a site uses Venatus?
-Look for Venatus in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker). We list a site here only when its current ads.txt or live ad setup points to Venatus.
+Look for Venatus in the site's ads.txt file, or paste the domain into our [ad network checker](/ad-network-checker).
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/joining.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/joining.mdx
index e68ece34..02fff0f6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/joining.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/joining.mdx
@@ -1,3 +1,3 @@
-## Who can join Venatus?
+Venatus works with gaming, sports, and entertainment sites. It doesn't publish a traffic minimum or region rule. You can send its publisher interest form.
-Venatus works with gaming, sports, and entertainment sites. It doesn't publish a traffic minimum, region rule, or content checklist. You can send its publisher interest form.
+A person on its team audits your site, and you must follow its Publisher Terms. Hate speech, adult content, illegal sharing or hacking, and promotion of drugs, tobacco, or firearms aren't allowed.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/rules.mdx b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/rules.mdx
index 1dcab4fd..9c473b0a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/content/venatus/rules.mdx
+++ b/app/(site)/(directories)/ad-networks/[slug]/content/venatus/rules.mdx
@@ -1,3 +1,3 @@
## What rules does Venatus set?
-Not public. Venatus describes curated demand and ad management, but not exclusivity, placement control, content rules, contract length, or notice.
+Venatus bans hate speech, adult content, illegal sharing or hacking, and promotion of drugs, tobacco, or firearms. Exclusivity, placement control, contract length, and notice are not public.
diff --git a/app/(site)/(directories)/ad-networks/[slug]/network-details.tsx b/app/(site)/(directories)/ad-networks/[slug]/network-details.tsx
index 326c04c7..4788b2b6 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/network-details.tsx
+++ b/app/(site)/(directories)/ad-networks/[slug]/network-details.tsx
@@ -50,10 +50,17 @@ function TabWords({ Words }: { Words?: MDXContent }) {
return Words ?
: null;
}
-/** Fact rows for one tab, or nothing when the network publishes none of them. */
-function factRows(rows: readonly { label: string; value: string | null; note?: string }[]): Fact[] {
- if (!rows.some((row) => row.value)) return [];
- return rows.map((row) => ({ label: row.label, value: row.value ?? , note: row.note }));
+type FactRow = { label: string; value: string | null; note?: string };
+
+/**
+ * Fact rows for one tab: each published fact on its own row, then one `Not public` row naming
+ * everything the network doesn't publish, so a tab doesn't read as a column of blanks.
+ */
+function factRows(rows: readonly FactRow[]): Fact[] {
+ const known: Fact[] = rows.filter((row) => row.value).map((row) => ({ label: row.label, value: row.value, note: row.note }));
+ // Later labels read in lower case, except names such as "Google standing".
+ const missing = rows.filter((row) => !row.value).map((row, index) => (index && !/^Google\b/.test(row.label) ? row.label.toLowerCase() : row.label));
+ return missing.length ? [...known, { label: "Not public", value: }] : known;
}
/**
@@ -70,17 +77,15 @@ export function NetworkDetails({ content, name, slug }: { content: AdNetworkCont
const keyNumbers = shown.map((item) => keyNumber(item, joining.includes(item)));
// Researched joining rows in network-facts.ts, in the mockup's order. "Not public" is a finding, not missing data.
- const joiningRows: Fact[] = facts ? facts.joining.map((row) => ({
- label: row.label,
- value: row.value === NOT_PUBLIC ? : row.value,
- note: row.note,
- })) : [];
- const payRows = facts ? factRows([
+ const joiningRows = facts ? factRows(facts.joining.map((row) => ({ ...row, value: row.value === NOT_PUBLIC ? null : row.value }))) : [];
+ const payFacts: FactRow[] = facts ? [
{ label: "Revenue share", value: facts.revenueShare },
{ label: "Pay day", value: facts.paymentTerms },
{ label: "Minimum payout", value: facts.paymentThreshold },
{ label: "Paid by", value: facts.paymentMethods.length ? facts.paymentMethods.join(", ") : null },
- ]) : [];
+ ] : [];
+ // A Pay tab with nothing published leaves the rows out and lets the words explain.
+ const payRows = payFacts.some((row) => row.value) ? factRows(payFacts) : [];
const tabs: UiTab[] = [
{ id: "joining", title: "Joining", rows: joiningRows, Words: Joining },
diff --git a/app/(site)/(directories)/ad-networks/[slug]/network-stats.tsx b/app/(site)/(directories)/ad-networks/[slug]/network-stats.tsx
index b5f5f3bd..178dfd71 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/network-stats.tsx
+++ b/app/(site)/(directories)/ad-networks/[slug]/network-stats.tsx
@@ -9,7 +9,6 @@ import { ColumnChart } from "@/app/ui/ad-networks/viz/columns";
import { Donut } from "@/app/ui/ad-networks/viz/donut";
import { formatNumber, formatSigned } from "@/app/ui/ad-networks/viz/format";
import { JoinedLeftBars } from "@/app/ui/ad-networks/viz/joined-left";
-import { PublisherBlocks } from "@/app/ui/ad-networks/viz/publisher-blocks";
import { SwitchFlow } from "@/app/ui/ad-networks/viz/switch-flow";
import { TypeScale } from "@/app/ui/ad-networks/viz/type-scale";
import { nicheName } from "@/app/ui/ad-networks/site-format";
@@ -52,6 +51,8 @@ const shortName = (name: string) => name.replace(/^Google /, "").replace(/ by Me
/** A row of blocks with only the blocks that have data. Nothing renders when none do. */
function Row({ blocks, layout }: { blocks: readonly ReactNode[]; layout: "1-1" | "2-1" | "1-1-1" | "2-1-1" }) {
const shown = blocks.filter(Boolean);
+ // A lone block takes the full width instead of leaving an empty column beside it.
+ if (shown.length === 1) return <>{shown}>;
return shown.length ? {shown} : null;
}
@@ -61,7 +62,7 @@ function Row({ blocks, layout }: { blocks: readonly ReactNode[]; layout: "1-1" |
* lib/ad-networks*.ts; each field's data run is in dev-space/ad-networks-data-contract.md.
*/
export function NetworkStats({ network, stats }: { network: AdNetworkListRow; stats: AdNetworkStatsReport }) {
- const { name, slug } = network;
+ const { name } = network;
if (!stats.listed) return null;
// How many sites use it?
@@ -72,10 +73,6 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
...(stats.change_year !== null ? [{ label: "sites in a year", value: formatSigned(stats.change_year), accent: stats.change_year > 0 }] : []),
];
const history = stats.history.map((row) => ({ label: monthShort.format(day(row.date)), fullLabel: monthLong.format(day(row.date)), value: row.listed }));
- const rankRows: RankedBar[] = stats.ranking
- .map((row, index) => ({ row, index }))
- .filter(({ row, index }) => row.count > 0 && (index < 5 || row.slug === slug))
- .map(({ row }) => ({ label: row.name, value: row.count, href: row.slug === slug ? undefined : `/ad-networks/${row.slug}`, highlight: row.slug === slug }));
// What kind of sites?
const topNiches = stats.niches.slice(0, 6);
@@ -85,11 +82,10 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
...(otherNiches > 0 ? [{ label: "Other", value: otherNiches, display: pct(otherNiches) }] : []),
];
const traffic = stats.traffic.map((row) => ({
- label: trafficLabel(row.key).replace(/^top /, ""),
+ label: trafficLabel(row.key),
value: row.count,
tone: row.key.startsWith("not") ? "n2" as const : "ac" as const,
}));
- const publishers = stats.publishers.slice(0, 5).map((row) => ({ label: row.label, count: row.count }));
// Joined, left, and switches.
const periods = timeline(stats.movement_periods ?? []);
@@ -99,6 +95,15 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
const age = stats.domain_age_strip;
const platforms = stats.platform_mix ?? [];
const measuredPlatforms = platforms.filter((row) => row.key !== "unknown");
+ // A short legend: the four most used platforms, the rest as Other, then Unknown.
+ const topPlatforms = [...measuredPlatforms].sort((a, b) => b.count - a.count).slice(0, 4);
+ const otherPlatforms = measuredPlatforms.filter((row) => !topPlatforms.includes(row)).reduce((sum, row) => sum + row.count, 0);
+ const unknownPlatforms = platforms.find((row) => row.key === "unknown")?.count ?? 0;
+ const platformParts = [
+ ...topPlatforms.map((row) => ({ label: row.label, value: row.count })),
+ ...(otherPlatforms > 0 ? [{ label: "Other", value: otherPlatforms }] : []),
+ ...(unknownPlatforms > 0 ? [{ label: "Unknown", value: unknownPlatforms, tone: "track" as const }] : []),
+ ];
const topEndings = stats.domain_endings.slice(0, 5);
const otherEndings = stats.domain_endings.slice(5).reduce((sum, row) => sum + (row.share ?? 0), 0);
const endings = [
@@ -122,11 +127,6 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
) : null,
- publishers.length ? (
-
-
-
- ) : null,
];
const moveBlocks = [
periods.length ? (
@@ -145,28 +145,29 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
) : null,
];
+ // Domain age is a wide timeline, so it gets its own row; platforms and endings share the next.
+ const ageBlock = age ? (
+
+ {stats.median_domain_age !== null ? (
+
+ ) : null}
+
+
+ ) : null;
const buildBlocks = [
- age ? (
-
- {stats.median_domain_age !== null ? (
-
- ) : null}
-
-
- ) : null,
measuredPlatforms.length ? (
({ label: row.label, value: row.count, ...(row.key === "unknown" ? { tone: "track" as const } : {}) }))}
+ parts={platformParts}
/>
) : null,
@@ -207,18 +208,13 @@ export function NetworkStats({ network, stats }: { network: AdNetworkListRow; st
) : null,
- rankRows.length ? (
-
-
-
- ) : null,
]} />
>
),
},
- { title: `What kind of sites use ${name}?`, has: kindBlocks.some(Boolean), content:
},
+ { title: `What kind of sites use ${name}?`, has: kindBlocks.some(Boolean), content:
},
{ title: `Which sites joined or left ${name}?`, has: moveBlocks.some(Boolean), content:
},
- { title: `How are ${name} sites built?`, has: buildBlocks.some(Boolean), content:
},
+ { title: `How are ${name} sites built?`, has: Boolean(ageBlock) || buildBlocks.some(Boolean), content: <>{ageBlock}
> },
{ title: "What else is in their ads.txt?", has: adsTxtBlocks.some(Boolean), content:
},
];
diff --git a/app/(site)/(directories)/ad-networks/[slug]/page.tsx b/app/(site)/(directories)/ad-networks/[slug]/page.tsx
index dbca9cae..1cdbac5a 100644
--- a/app/(site)/(directories)/ad-networks/[slug]/page.tsx
+++ b/app/(site)/(directories)/ad-networks/[slug]/page.tsx
@@ -77,6 +77,7 @@ export default async function AdNetworkPage({ params }: { params: Promise<{ slug
noun="sites"
route={`/ad-networks/${slug}`}
scope={{ network: slug }}
+ sorts={["traffic", "oldest", "newest", "domain"]}
/>
) : null}
diff --git a/app/(site)/(directories)/ad-networks/content/article.mdx b/app/(site)/(directories)/ad-networks/content/article.mdx
index 8fee905b..cd308803 100644
--- a/app/(site)/(directories)/ad-networks/content/article.mdx
+++ b/app/(site)/(directories)/ad-networks/content/article.mdx
@@ -1,13 +1,87 @@
+## How do you choose an ad network?
+
+Start with the networks you can join today, then look at what sites like yours run. Four steps cover most of it:
+
+1. Sort the list by `Easiest to join` to see which networks take a site of your size.
+2. Open a network's page and filter its sites by your niche. The traffic column shows whether sites your size run it. The [niches page](/ad-networks/niches) shows the same thing from the other side: the networks each niche uses most.
+3. Compare the deal on each network's page: revenue share, when it pays, the minimum payout, and its rules, where the network publishes them.
+4. Paste a site you'd like to grow into in the [ad network checker](/ad-network-checker) to see exactly who runs its ads.
+
+
+Many sites start with a self-serve network such as Google AdSense and move to a managed network once they pass its minimum. Some managed networks run a separate program for smaller sites, such as Journey by Mediavine.
+
+
## What do ad networks require to join?
Most ad networks set a minimum to join, shown on each card under "To join". Many count monthly traffic, and some, such as Mediavine, count the ad revenue your site already earns. Self-serve networks such as Google AdSense take sites of any size. Where a card says "Not public", the network doesn't publish a fixed rule.
-Networks count traffic in different ways. A session is one visit, and a pageview is one page loaded, so one session often includes several pageviews. A minimum of 50,000 sessions is harder to reach than 50,000 pageviews.
+Networks count traffic in different ways, so check which word the rule uses:
+
+
+Every page loaded. One visit that reads three articles is three pageviews.
+Visits. One session often includes several pageviews, so 50,000 sessions is harder to reach than 50,000 pageviews.
+People. Someone who comes back five times in a month usually counts once.
+What your ads already earn, usually over a year. Mediavine uses this instead of traffic.
+
Traffic isn't the only rule. Many networks also check where your visitors come from, whether your content is original, and whether your site follows Google's ad policies. Each network's page lists its full rules.
-## How do we confirm a site uses a network?
+## How do you read a network card?
+
+The big number is how many sites we list for that network. Next to it, `confirmed` counts the sites where our last check found the network. The gap between the two is sites we haven't seen it on lately.
+
+A network with 0 sites is one we track but haven't confirmed on any site yet.
+
+## How do we build this list?
+
+We find sites, then check each one ourselves. A site goes on a network's page only when the site's own files or code show the network. Nothing here comes from a paid listing.
+
+### Where do the sites come from?
+
+Each week we read the public seller lists that networks publish, called `sellers.json`, and official publisher lists such as the one EthicalAds keeps. When we started, we also used public lists of sites by ad network. A list only tells us where to look. It never puts a site on a network by itself.
+
+### What confirms a site uses a network?
+
+We read the site's `ads.txt` file, the public list of companies allowed to sell its ad space, and sometimes its homepage code.
+
+| What we find | What we say |
+| --- | --- |
+| A `MANAGERDOMAIN` line in `ads.txt` names the network | The network manages the site's ads. It's the site's main ad network. |
+| The page loads the network's own ad code, usually with a matching `ads.txt` line | The site uses the network. |
+| For Google AdSense, the same publisher ID in `ads.txt` and in the page's ad code | The site uses AdSense. |
+| Only a seller line, or only a mention in a network's seller list | Not enough. The site stays off the list. |
+
+### What do "listed" and "confirmed live" mean?
+
+`Confirmed live` means we found the network on the site and it hasn't gone missing long enough to count as not seen lately. `Listed` adds the sites where we haven't seen it lately.
+
+| Status | When it happens |
+| --- | --- |
+| Confirmed live | A check found the network, and it hasn't been missing for two checks yet. One missed check doesn't change this. |
+| Not seen lately | Two checks at least 48 hours apart didn't find it. It stays listed and may come back. |
+| Ended | Three checks over seven days or more didn't find it. The site leaves the network's list but keeps the history in the checker. |
+
+A check that fails, such as a timeout or a blocked request, never counts as missing. A check that works but doesn't find the network does: a readable `ads.txt` file without it, or no `ads.txt` file at all.
+
+### How often do we check again?
+
+Checks run every hour in small batches. Each confirmed site gets checked about once a week. When a network goes missing, we check again within a day or two. Sites with no network we track get another look in about three months.
+
+### Where do traffic, niche, domain age, and platform come from?
+
+| Fact | Where it comes from | How often |
+| --- | --- | --- |
+| Traffic | The site's rank group in Google's [Chrome UX Report](https://developer.chrome.com/docs/crux), a list of the million most visited sites by Chrome users: top 10k, top 100k, or top 1M. `Not ranked` means the site wasn't in this month's Chrome UX Report list. That doesn't mean zero traffic: the list only covers sites with enough Chrome visitors. | Monthly |
+| Niche | We sort each site into one of 20 niches. Sites we aren't sure about stay unsorted. | Weekly, for new sites |
+| Domain age | The registration date in the domain registry's public RDAP record. | Daily, for new sites |
+| Platform | Signs in the homepage code, such as WordPress. | Daily, refreshed every 30 days |
+| Publisher | The business name in the network's own seller list, when the domain matches. | Weekly |
+
+When we don't know a fact, the page says `Not listed` instead of guessing. Traffic groups use Chrome UX Report data from Google, under the [CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0/).
-We read each site's own ads.txt file, the public list of companies allowed to sell its ad space. When the file names a network as its ad manager, or the site's pages load that network's ad code, the site counts as confirmed. A network's seller list can point us to a site, but it never confirms one on its own.
+### What do we leave out?
-We re-check every site regularly, and a site that drops a network loses its confirmed status. That's why a network's confirmed count can be lower than its total.
+- Sites we found but couldn't confirm.
+- Networks outside the 44 we track.
+- Personal names from seller lists. We only show business names.
+- Visit counts and earnings. There's no public source we can check them against.
diff --git a/app/(site)/(directories)/ad-networks/join-rules.ts b/app/(site)/(directories)/ad-networks/join-rules.ts
index 6f80644d..37b48e2a 100644
--- a/app/(site)/(directories)/ad-networks/join-rules.ts
+++ b/app/(site)/(directories)/ad-networks/join-rules.ts
@@ -12,20 +12,23 @@ export function trafficRule(facts: AdNetworkFacts) {
const rule = facts.minTraffic;
if (!rule) return null;
if (rule.amount === 0) return "No traffic minimum";
- return `${rule.amount.toLocaleString("en-US")} ${rule.unit} a month`;
+ return rule.label ?? `${rule.amount.toLocaleString("en-US")} ${rule.unit} a month`;
}
-// Key numbers about pay, fees, or contracts. Everything else is a rule for joining.
-const payNumber = /pay|share|fee|payout|terms|threshold|notice|timing|schedule|floor|minimums?$/i;
+// Key numbers about pay, fees, or contracts.
+const payNumber = /pay|share|split|fee|payout|terms|threshold|notice|timing|schedule|floor|minimums?$/i;
+// Key numbers that are a bar to clear: traffic, users, or revenue to join. Others, such as a typical
+// CPM or a review time, stay plain key numbers and never become the page's joining rule.
+const joinNumber = /join|traffic|users|visitors|pageviews|sessions|revenue benchmark/i;
+
+// Notes that say the number isn't a rule anyone has to meet, such as a benchmark or a referral bar.
+const notARule = /not a general minimum|not the main rule/i;
/** Key numbers that say what it takes to join, such as revenue or traffic to apply. */
export function joiningNumbers(facts: AdNetworkFacts) {
- return facts.keyNumbers.filter((item) => !payNumber.test(item.label));
+ return facts.keyNumbers.filter((item) => !payNumber.test(item.label) && joinNumber.test(item.label) && !notARule.test(item.note ?? ""));
}
-// Notes that say the number isn't a rule anyone has to meet.
-const notARule = /not a general minimum|not the main rule/i;
-
/**
* A joining key number as one phrase: the value, then the first part of its note, worded the
* way people say it. "$5,000" with "in annual ad revenue" reads "$5,000 ad revenue a year".
@@ -44,9 +47,9 @@ export function joinPhrase(item: AdNetworkFacts["keyNumbers"][number]) {
export function joinLabel(slug: string): { value: string } {
const facts = networkFacts(slug);
if (!facts) return { value: "Not listed" };
- const rule = trafficRule(facts);
+ const rule = facts.joinSummary ?? trafficRule(facts);
if (rule) return { value: rule };
- const first = joiningNumbers(facts).find((item) => !notARule.test(item.note ?? ""));
+ const first = joiningNumbers(facts)[0];
return { value: first ? joinPhrase(first) : NOT_PUBLIC };
}
@@ -57,9 +60,9 @@ export function joinLabel(slug: string): { value: string } {
export function joinRule(slug: string): string | null {
const facts = networkFacts(slug);
if (!facts) return null;
- const rule = trafficRule(facts);
+ const rule = facts.joinSummary ?? trafficRule(facts);
if (rule) return rule;
- const first = joiningNumbers(facts).find((item) => !notARule.test(item.note ?? ""));
+ const first = joiningNumbers(facts)[0];
return first ? joinPhrase(first) : null;
}
diff --git a/app/(site)/(directories)/ad-networks/network-facts.ts b/app/(site)/(directories)/ad-networks/network-facts.ts
index 101dcf26..bcc067c6 100644
--- a/app/(site)/(directories)/ad-networks/network-facts.ts
+++ b/app/(site)/(directories)/ad-networks/network-facts.ts
@@ -13,7 +13,13 @@ export type AdNetworkFacts = {
checkedAt: string; // YYYY-MM-DD, the day the sources were read
keyNumbers: AdNetworkKeyNumber[]; // up to three, most useful first
joining: { label: string; value: string; note?: string; sourceUrl: string | null }[];
- minTraffic: { amount: number; unit: "sessions" | "pageviews" | "visitors" } | null; // monthly; null when there is no public rule
+ // Monthly, for sorting by how easy a network is to join. 0 only when the network says it has no
+ // minimum; null when it publishes none. `label` keeps the network's own wording, such as
+ // "More than 100,000 visits a month", wherever the rule is shown.
+ minTraffic: { amount: number; unit: "sessions" | "pageviews" | "visitors"; label?: string } | null;
+ // The joining rule in one phrase, for a rule with alternative ways in that a single number would
+ // drop, such as "$5,000 ad revenue or 2 million pageviews a month". Shown before any other rule.
+ joinSummary?: string;
revenueShare: string | null;
paymentTerms: string | null;
paymentThreshold: string | null;
@@ -23,48 +29,48 @@ export type AdNetworkFacts = {
// Keyed by network slug.
export const adNetworkFacts: Record = {
- adapex: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 60", sourceUrl: "https://adapex.io/faqs/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Ad Manager via MCM", sourceUrl: "https://adapex.io/faqs/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher FAQ", url: "https://adapex.io/faqs/" }] },
- aditude: { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Official publisher guidance", url: "https://www.aditude.com/blog/the-5-questions-every-publisher-should-ask-their-monetization-partner" }] },
- adnimation: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 35", sourceUrl: "https://www.adnimation.com/faqs/" }], joining: [{ label: "Traffic", value: "Substantial, no figure stated", note: "MAP is a separate program with no minimum", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No gambling, pornography, or drugs", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Google standing", value: "Follow Google policy guidelines", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 35", paymentThreshold: null, paymentMethods: ["Direct bank payment", "PayPal by arrangement"], sources: [{ label: "Publisher FAQ", url: "https://www.adnimation.com/faqs/" }, { label: "MAP program terms, separate program", url: "https://www.adnimation.com/map-terms-conditions/" }] },
- adpushup: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Your share", value: "80%", note: "in older public terms; check your signed agreement", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2020/02/AdPushup-Terms-of-Service-v2.0-WebSite-Version1.pdf" }, { label: "Payment minimum", value: "$50", note: "in older public terms", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2020/02/AdPushup-Terms-of-Service-v2.0-WebSite-Version1.pdf" }, { label: "Pay day", value: "Net 45", note: "in older public terms", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2020/02/AdPushup-Terms-of-Service-v2.0-WebSite-Version1.pdf" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "80% in older published terms; current agreement may differ", paymentTerms: "Net 45 in older published terms", paymentThreshold: "$50 in older published terms", paymentMethods: [], sources: [{ label: "Publisher terms, revised 2018", url: "https://www.adpushup.com/wp-content/uploads/2020/02/AdPushup-Terms-of-Service-v2.0-WebSite-Version1.pdf" }, { label: "Publisher onboarding", url: "https://www.adpushup.com/publisher/get-started/" }] },
- "amazon-publisher-services": { checkedAt: "2026-10-16", keyNumbers: [{ label: "UAM fee", value: "10%", note: "taken from SSP bid prices; Unified Ad Marketplace only", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Payment minimum", value: "$5", note: "UAM", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Pay day", value: "Net 60", note: "UAM", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Worldwide", note: "For Unified Ad Marketplace only", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Ad Manager", note: "For Unified Ad Marketplace only", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60 for UAM", paymentThreshold: "$5 for UAM", paymentMethods: [], sources: [{ label: "UAM publisher update", url: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }] },
- "anymind-anymanager": { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "AnyManager overview", url: "https://anymindgroup.com/news/press-release/11388/" }, { label: "AnyMind IR FAQ", url: "https://anymindgroup.com/ir/faq/" }] },
- "buysellads-carbon-ads": { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Carbon Tag or API", sourceUrl: "https://www.buysellads.com/publishers" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Carbon Ads media kit", url: "https://www.buysellads.com/hubfs/Carbon%20Ads%20Media%20Kit.pdf" }, { label: "Carbon Ads publisher page", url: "https://discover.buysellads.com/carbon" }] },
- clickio: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "100,000 to 1,000,000", note: "monthly pageviews; varies by region, and revenue can also qualify a site", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Minimum earnings", value: "$500", note: "a month; may be enforced after the first three months", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Pay day", value: "Net 60", sourceUrl: "https://docs.clickio.com/books/get-started/page/payments-billing" }], joining: [{ label: "Traffic", value: "100,000 to 1,000,000 pageviews by region", note: "Monthly; $500 in monthly revenue may qualify below the threshold", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Visitor location", value: "Sanctioned countries excluded", note: "Pageview thresholds also vary by region", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Content", value: "Follow AdSense policies and third-party rights rules", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Publish ads.txt; provide GA4 or a six-month report if requested", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Site history", value: "Six months of traffic data if external verification is unavailable", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Ad revenue", value: "$500 a month", note: "Possible traffic alternative; ongoing minimum account earnings", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60", paymentThreshold: "Varies by method: $100 equivalent for ACH/eCheck/SEPA, PayPal and check; $200 wire; some other methods have separate thresholds", paymentMethods: ["ACH", "eCheck", "SEPA", "Wire", "Check", "PayPal", "WebMoney", "Payoneer"], sources: [{ label: "Entry standards", url: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Payments and billing", url: "https://docs.clickio.com/books/get-started/page/payments-billing" }] },
- concert: { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Concert terms surfaced publicly (advertiser product, not publisher terms)", url: "https://admanager.concert.io/terms" }] },
- ethicalads: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Your share", value: "70%", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Payment minimum", value: "$50", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Pay day", value: "Monthly", note: "target by the 15th", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }], joining: [{ label: "Traffic", value: "No minimum stated", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Meet the publisher policy", note: "Ads must appear above the fold on desktop and mobile", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "70%", paymentTerms: "Monthly; target payment date is the 15th", paymentThreshold: "$50", paymentMethods: ["Stripe Connect / bank transfer", "PayPal", "OpenCollective", "GitHub Sponsors"], sources: [{ label: "Publisher policy", url: "https://www.ethicalads.io/publisher-policy/" }, { label: "Terms of service", url: "https://www.ethicalads.io/terms-of-service/" }] },
- ezoic: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Users to join", value: "250,000", note: "monthly active users, for new sites", sourceUrl: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Your share", value: "82%", note: "at least, of net ad revenue", sourceUrl: "https://www.ezoic.com/terms" }, { label: "Payment minimum", value: "$20", sourceUrl: "https://www.ezoic.com/terms" }], joining: [{ label: "Traffic", value: "250,000 monthly active users", note: "Incubator may accept smaller sites", sourceUrl: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original content in a supported language", sourceUrl: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Google standing", value: "Comply with Google and AdSense policies", note: "AdSense approval is not required for most sites", sourceUrl: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Must connect", value: "Google Analytics for traffic verification", sourceUrl: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 250000, unit: "visitors" }, revenueShare: "At least 82% of net ad revenue under published Terms, unless another agreement applies", paymentTerms: "Approximately 35 days after the advertiser pays, under published Terms", paymentThreshold: "$20", paymentMethods: ["PayPal", "Payoneer bank transfer", "Check"], sources: [{ label: "Current eligibility requirements", url: "https://osticket.ezoic.com/kb/article/getting-started-ezoics-requirements" }, { label: "Terms", url: "https://www.ezoic.com/terms" }, { label: "Payment help", url: "https://support.ezoic.com/kb/article/ezoic-payments?lang=en-US&lang=it%3Fid%3Dezoic-payments" }] },
- freestar: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "1,000,000", note: "monthly pageviews; Freestar says usually, so confirm with its team", sourceUrl: "https://freestar.com/contact-us/" }, { label: "From top markets", value: "50%", note: "of traffic from the US, UK, Canada, New Zealand, or Australia", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }], joining: [{ label: "Traffic", value: "Usually 1,000,000 pageviews", note: "Monthly", sourceUrl: "https://freestar.com/contact-us/" }, { label: "Visitor location", value: "At least 50% from the US, UK, Canada, New Zealand, or Australia", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Content", value: "Original, human-focused, brand-safe content", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Google standing", value: "Good standing with major ad providers", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Must connect", value: "Provide GA4 access for review", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 1000000, unit: "pageviews" }, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher quality requirements", url: "https://freestar.com/publisher-quality-requirements/" }, { label: "Publisher contact", url: "https://freestar.com/contact-us/" }] },
- "geniee-ssp": { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "GENIEE corporate site", url: "https://geniee.co.jp/" }, { label: "GENIEE SSP site", url: "https://genieesspv.jp/" }] },
- "google-adsense": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Your share", value: "80%", note: "after the advertiser platform fee; about 68% with Google Ads demand", sourceUrl: "https://support.google.com/adsense/answer/180195?hl=en" }, { label: "Payment minimum", value: "$100", note: "in US dollars", sourceUrl: "https://support.google.com/adsense/answer/1709871?hl=en" }, { label: "Pay days", value: "21st to 26th", note: "of each month", sourceUrl: "https://support.google.com/adsense/answer/7164701?hl=en" }], joining: [{ label: "Traffic", value: "No minimum stated", sourceUrl: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Visitor location", value: "Sign-up is available in listed countries", sourceUrl: "https://support.google.com/adsense/answer/13402307?hl=en" }, { label: "Content", value: "Original, high-quality, policy-compliant content", sourceUrl: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Access to the site HTML", note: "Needed to verify and place ad code", sourceUrl: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "80% after the advertiser platform fee for AdSense for Content", paymentTerms: "Monthly; payments are issued between the 21st and 26th when the balance reaches threshold and there are no holds", paymentThreshold: "$100 USD, with equivalent thresholds by account currency", paymentMethods: ["Check", "EFT", "SEPA", "Wire transfer", "PayPal Hyperwallet where available"], sources: [{ label: "Revenue share", url: "https://support.google.com/adsense/answer/180195?hl=en" }, { label: "Payment threshold", url: "https://support.google.com/adsense/answer/1709871?hl=en" }, { label: "Payment schedule", url: "https://support.google.com/adsense/answer/7164701?hl=en" }, { label: "Eligibility", url: "https://support.google.com/adsense/answer/9724?hl=en" }] },
- infolinks: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Your share", value: "70%", note: "for In-Text ads", sourceUrl: "https://sites0001.infolinks.com/service-agreement?email=&name=&url=" }, { label: "Pay day", value: "Net 45", note: "working days", sourceUrl: "https://sites0001.infolinks.com/service-agreement?email=&name=&url=" }, { label: "Payment minimum", value: "$50", note: "for eCheck", sourceUrl: "https://sites0001.infolinks.com/support/payments/can-i-receive-my-payment-via-echeck" }], joining: [{ label: "Traffic", value: "No minimum pageviews or visitors", sourceUrl: "https://sites0001.infolinks.com/support/quality/what-are-the-eligibility-criteria-for-my-site-to-qualify-with-infolinks" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No illegal or offensive content", sourceUrl: "https://sites0001.infolinks.com/support/quality/what-are-the-eligibility-criteria-for-my-site-to-qualify-with-infolinks" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install the Infolinks script", sourceUrl: "https://sites0001.infolinks.com/support/integration/how-do-i-integrate-infolinks-into-my-website" }, { label: "Approval time", value: "Usually 48 hours", sourceUrl: "https://sites0001.infolinks.com/support/account/how-do-i-sign-up-as-an-infolinks-publisher" }], minTraffic: null, revenueShare: "70% for In-Text ad units; other format terms vary", paymentTerms: "Net 45 working days after the month ends under the public agreement", paymentThreshold: "Varies by method; eCheck $50", paymentMethods: ["ACH", "eCheck", "Payoneer", "PayPal", "Western Union"], sources: [{ label: "Publisher eligibility", url: "https://sites0001.infolinks.com/support/quality/what-are-the-eligibility-criteria-for-my-site-to-qualify-with-infolinks" }, { label: "Service agreement", url: "https://sites0001.infolinks.com/service-agreement?email=&name=&url=" }, { label: "Payment options", url: "https://sites0001.infolinks.com/support/payments/do-i-pay-fees-when-receiving-my-infolinks-payment" }] },
- "journey-by-mediavine": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "More than 1,000", note: "monthly sessions", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }], joining: [{ label: "Traffic", value: "More than 1,000 sessions", note: "Monthly", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original, updated, human-created, brand-safe content", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Google standing", value: "No active AdSense or Ad Exchange issues", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Must connect", value: "Install the Grow plugin", note: "Journey requirement", sourceUrl: "https://www.journeymv.com/affiliates-faq/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 1000, unit: "sessions" }, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Mediavine approval requirements, including Journey", url: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Journey criteria", url: "https://www.journeymv.com/affiliates-faq/" }] },
- "media-net": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 30", sourceUrl: "https://www.media.net/legal/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original content; prohibited topics are excluded", sourceUrl: "https://www.media.net/legal/inventorypolicies/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Publish an authorized ads.txt file", sourceUrl: "https://www.media.net/legal/inventorypolicies/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 30; monthly revenue payments under the Publisher Agreement", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher Agreement", url: "https://www.media.net/legal/" }, { label: "Inventory policies", url: "https://www.media.net/legal/inventorypolicies/" }] },
- mediavine: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Revenue to join", value: "$5,000", note: "in annual ad revenue", sourceUrl: "https://help.mediavine.com/mediavine-official" }, { label: "Your share", value: "75%", sourceUrl: "https://help.mediavine.com/mediavine-official" }, { label: "Pay day", value: "Net 65", sourceUrl: "https://help.mediavine.com/mediavine-payment-faq" }], joining: [{ label: "Traffic", value: "No traffic minimum listed", note: "Mediavine sets an ad revenue minimum instead", sourceUrl: "https://help.mediavine.com/mediavine-official" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original, quality, evergreen content", sourceUrl: "https://help.mediavine.com/mediavine-official" }, { label: "Google standing", value: "No active AdSense ban", note: "You do not need prior AdSense use", sourceUrl: "https://help.mediavine.com/mediavine-official" }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "$5,000 a year", note: "Minimum annual ad revenue", sourceUrl: "https://help.mediavine.com/mediavine-official" }], minTraffic: null, revenueShare: "75%", paymentTerms: "Net 65; paid on the 5th or first business day after it", paymentThreshold: "$100 for most methods; higher for some international methods", paymentMethods: ["PayPal", "Domestic ACH", "International ACH", "US wire", "International wire"], sources: [{ label: "Mediavine Official requirements", url: "https://help.mediavine.com/mediavine-official" }, { label: "Payment FAQ", url: "https://help.mediavine.com/mediavine-payment-faq" }, { label: "Payment methods and minimums", url: "https://help.mediavine.com/mediavine-payment-methods" }] },
- mgid: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Your share", value: "65%", note: "on a published regional offer; current order terms may differ", sourceUrl: "https://pr.mgid.com/monetize" }, { label: "Pay day", value: "Net 30", note: "on the same offer", sourceUrl: "https://pr.mgid.com/monetize" }, { label: "Payment minimums", value: "$50 to $1,000", note: "varies by payment method", sourceUrl: "https://pr.mgid.com/monetize" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No adult, illegal, hateful, or infringing content", sourceUrl: "https://www.mgid.com/services/publishers-tos" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install MGID ad units and code", sourceUrl: "https://www.mgid.com/services/publishers-tos" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 30 in regional offer; current Publisher Terms and order control", paymentThreshold: "Method-specific; published offer lists $50 to $1,000", paymentMethods: ["Bank transfer", "PayPal", "Tipalti", "Paymaster24"], sources: [{ label: "Regional publisher offer", url: "https://pr.mgid.com/monetize" }, { label: "Publisher terms", url: "https://www.mgid.com/services/publishers-tos" }] },
- "monetizemore-pubguru": { checkedAt: "2026-10-16", keyNumbers: [{ label: "To join Premium", value: "$5,000", note: "monthly ad revenue or 2 million monthly pageviews", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }], joining: [{ label: "Traffic", value: "2,000,000 pageviews", note: "Monthly, an alternative to the revenue threshold", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "$5,000 a month", note: "Alternative to the 2 million monthly pageview threshold", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "PubGuru Premium", url: "https://www.monetizemore.com/solutions/pubguru-premium/" }, { label: "MonetizeMore FAQ", url: "https://www.monetizemore.com/frequently-asked-questions/" }] },
- monumetric: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "10,000", note: "monthly pageviews, Propel program", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Pay day", value: "Net 60", sourceUrl: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }, { label: "Payment minimum", value: "$10", sourceUrl: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }], joining: [{ label: "Traffic", value: "At least 10,000 pageviews", note: "Monthly", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Visitor location", value: "At least 50% from the US, UK, Canada, or Australia", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Content", value: "English; no pornography, drugs, hate speech, or copyrighted content", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 10000, unit: "pageviews" }, revenueShare: null, paymentTerms: "Net 60; paid monthly within the first ten business days", paymentThreshold: "$10; balance rolls forward below this amount", paymentMethods: ["US direct deposit", "International PayPal", "Payoneer in some cases"], sources: [{ label: "Eligibility requirements", url: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Payment terms", url: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }] },
- "newor-media": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic for Catapult", value: "60,000", note: "US pageviews a month", sourceUrl: "https://newormedia.com/programs" }, { label: "Pay day", value: "Net 45", note: "in the platform agreement; the FAQ says Net 30", sourceUrl: "https://newormedia.com/node/296" }], joining: [{ label: "Traffic", value: "No minimum for Elevate", note: "Catapult: 60,000 US pageviews; Premier: 420,000 US pageviews monthly", sourceUrl: "https://newormedia.com/programs" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "English site with navigation; follow Google ad policies", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Google standing", value: "Follow Google ad policies", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Must connect", value: "Google Ad Manager account", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Approval time", value: "Usually 24 to 48 hours", note: "For Elevate review", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Exclusivity", value: "Required", note: "Newor Media says all publishers must be exclusive", sourceUrl: "https://newormedia.com/elevatefaqs" }], minTraffic: null, revenueShare: null, paymentTerms: "Net 45 in platform agreement; FAQ says Net 30", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Programs", url: "https://newormedia.com/programs" }, { label: "Elevate FAQ", url: "https://newormedia.com/elevatefaqs" }, { label: "Platform agreement", url: "https://newormedia.com/node/296" }, { label: "Payment FAQ", url: "https://newormedia.com/faqs/what-are-your-payment-terms" }] },
- nitropay: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Payment minimum", value: "None", note: "above the transaction fee", sourceUrl: "https://nitropay.com/docs/" }, { label: "Pay day", value: "Net 7", sourceUrl: "https://nitropay.com/docs/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 7 per public docs archive", paymentThreshold: "No stated minimum; earnings must exceed transaction fee", paymentMethods: [], sources: [{ label: "NitroPay docs archive", url: "https://nitropay.com/docs/" }, { label: "Bonus share terms", url: "https://nitropay.com/bonus/" }] },
- "opti-digital": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day, Managed Inventory", value: "Net 45", sourceUrl: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }, { label: "Pay day, Managed Account", value: "Net 60", note: "for applicable demand", sourceUrl: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 45 for Managed Inventory; Net 60 for applicable demand under Managed Account; exact setup is in the order", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Payment terms by setup", url: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }, { label: "Invoice flow", url: "https://knowledge-base.optidigital.com/knowledge/how-is-the-invoicing-working-at-opti-digital-when-will-i-get-paid" }] },
- playwire: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "100,000 to 500,000", note: "monthly pageviews; Playwire's pages differ", sourceUrl: "https://www.playwire.com/qualification-criteria" }, { label: "Pay day", value: "Net 60", sourceUrl: "https://www.playwire.com/faq" }], joining: [{ label: "Traffic", value: "500,000 monthly pageviews or 1,000 daily active users", note: "Qualification page separately suggests applying from 100,000 monthly pageviews", sourceUrl: "https://www.playwire.com/faq" }, { label: "Visitor location", value: "At least 20% of traffic from the US", note: "Qualification guidance", sourceUrl: "https://www.playwire.com/qualification-criteria" }, { label: "Content", value: "Unique, original content", sourceUrl: "https://www.playwire.com/qualification-criteria" }, { label: "Google standing", value: "Not blacklisted by Google or major ad providers", sourceUrl: "https://www.playwire.com/qualification-criteria" }, { label: "Must connect", value: "Implement the Playwire SDK", note: "Required to access its demand", sourceUrl: "https://www.playwire.com/faq" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Qualification criteria", url: "https://www.playwire.com/qualification-criteria" }, { label: "Publisher FAQ", url: "https://www.playwire.com/faq" }] },
- pubfuture: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 30", sourceUrl: "https://pubfuture.com/?from=chapterpage" }, { label: "Payment minimum", value: "$50", sourceUrl: "https://pubfuture.com/?from=chapterpage" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 30", paymentThreshold: "$50", paymentMethods: ["PayPal", "Payoneer", "Bank transfer", "Bitcoin"], sources: [{ label: "Publisher FAQ", url: "https://pubfuture.com/?from=chapterpage" }, { label: "PubFuture publisher case study", url: "https://blog.pubfuture.com/the-secret-to-400-more-revenue-for-h5-game-sites-pubfutures-winning-formula/1007/" }] },
- pubgalaxy: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Suggested traffic", value: "100,000", note: "monthly pageviews; not a hard minimum", sourceUrl: "https://www.pubgalaxy.com/learn-center/" }, { label: "Your share", value: "85%", note: "at least, of partner net revenue; at least 65% of direct net revenue", sourceUrl: "https://www.pubgalaxy.com/terms-and-conditions/" }, { label: "Payment minimum", value: "$50", note: "PayPal; $100 wire", sourceUrl: "https://www.pubgalaxy.com/terms-and-conditions/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "At least 85% of net revenue from ad partners and 65% from direct deals under published terms", paymentTerms: "Within 35 days after month end, subject to PubGalaxy receiving advertiser funds", paymentThreshold: "$50 PayPal; $100 wire", paymentMethods: ["PayPal", "Wire transfer"], sources: [{ label: "Publisher Learn Center", url: "https://www.pubgalaxy.com/learn-center/" }, { label: "Publisher terms", url: "https://www.pubgalaxy.com/terms-and-conditions/" }] },
- publift: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Revenue to join", value: "More than $2,000", note: "monthly ad revenue, typically", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Pageview signal", value: "500,000+", note: "a month; a signal, not the main rule", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Payment minimum", value: "$200", note: "in Publift's comparison table", sourceUrl: "https://www.publift.com/blog/the-best-cpm-ad-network-for-publishers" }], joining: [{ label: "Traffic", value: "500,000 pageviews is a secondary signal", note: "Monthly; revenue is the primary qualifying metric", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Visitor location", value: "No location-based limit stated", note: "Publift says it does not discriminate by traffic origin", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Content", value: "Useful, safe, original content", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "More than $2,000 a month", note: "Primary qualifying metric, in USD", sourceUrl: "https://www.publift.com/blog/publift-requirements" }], minTraffic: null, revenueShare: null, paymentTerms: "Google revenue: Net 30; other network revenue: Net 90 in Publift's current comparison article", paymentThreshold: "$200 in Publift's published comparison table", paymentMethods: ["Direct bank transfer"], sources: [{ label: "2026 requirements", url: "https://www.publift.com/blog/publift-requirements" }, { label: "2026 publisher payment comparison", url: "https://www.publift.com/blog/ezoic-vs-adsense-vs-publift" }] },
- publir: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pro fee", value: "15%", note: "Publir's fee on its Pro service; custom ads use a separate split", sourceUrl: "https://publir.com/app/pricing" }, { label: "Custom ad share", value: "50/50", note: "publisher and Publir, Net 60, in the service agreement", sourceUrl: "https://publir.com/service_agreement" }], joining: [{ label: "Traffic", value: "No traffic limit", sourceUrl: "https://publir.com/app/pricing" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60 for custom ad revenue under service agreement", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Pricing", url: "https://publir.com/app/pricing" }, { label: "Service agreement", url: "https://publir.com/service_agreement" }] },
- "publisher-collective": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Payment minimum", value: "€500", sourceUrl: "https://www.publisher-collective.com/partners-terms-conditions" }], joining: [{ label: "Traffic", value: "No numeric minimum stated", sourceUrl: "https://www.publisher-collective.com/partners-terms-conditions" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Own or license the media; no prohibited content", sourceUrl: "https://www.publisher-collective.com/partners-terms-conditions" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Integrate its systems and ad tags", sourceUrl: "https://www.publisher-collective.com/partners-terms-conditions" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Paid after advertiser payment; no fixed interval is published in the partner terms", paymentThreshold: "€500", paymentMethods: ["Bank transfer; GBP, EUR, or USD"] , sources: [{ label: "Partner terms", url: "https://www.publisher-collective.com/partners-terms-conditions" }, { label: "Publisher FAQ", url: "https://www.publisher-collective.com/faq" }, { label: "Google Ad Exchange article", url: "https://www.publisher-collective.com/blog/google-ad-exchange" }] },
- pubnation: { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Official website", url: "https://pubnation.com/" }] },
- pubpower: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 0 or Net 30", note: "Net 0 above $3,000 a month in revenue", sourceUrl: "https://help.pubpower.io/article/payment-methods-terms" }, { label: "Payoneer minimum", value: "$50", sourceUrl: "https://help.pubpower.io/article/payment-methods-terms" }, { label: "Bank transfer minimum", value: "$1,000", sourceUrl: "https://help.pubpower.io/article/payment-methods-terms" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 0 above $3,000 monthly revenue; otherwise Net 30", paymentThreshold: "Method-specific: $50 Payoneer, $100 PayPal, $100 to $1,000 crypto, or $1,000 bank", paymentMethods: ["Bank transfer", "PayPal", "Payoneer", "Cryptocurrency"], sources: [{ label: "Payment methods and terms", url: "https://help.pubpower.io/article/payment-methods-terms" }] },
- raptive: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "25,000", note: "monthly pageviews", sourceUrl: "https://raptive.com/creators/" }, { label: "Your share", value: "75%", sourceUrl: "https://raptive.com/fbp/" }, { label: "Pay day", value: "Net 45", sourceUrl: "https://help.raptive.com/hc/en-us/articles/202052255-When-do-I-get-paid" }], joining: [{ label: "Traffic", value: "At least 25,000 pageviews", note: "Monthly", sourceUrl: "https://raptive.com/creators/" }, { label: "Visitor location", value: "Majority from the US, Canada, UK, Australia, or New Zealand", sourceUrl: "https://raptive.com/creators/" }, { label: "Content", value: "100% original content", sourceUrl: "https://raptive.com/creators/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Set up Google Analytics", sourceUrl: "https://raptive.com/creators/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 25000, unit: "pageviews" }, revenueShare: "75%", paymentTerms: "Net 45; paid on the 15th", paymentThreshold: "$25; $100 for wire transfer", paymentMethods: ["ACH", "PayPal", "Wire transfer"], sources: [{ label: "Creator eligibility", url: "https://raptive.com/creators/" }, { label: "Share information", url: "https://raptive.com/fbp/" }, { label: "Payment FAQ", url: "https://help.raptive.com/hc/en-us/articles/202052255-When-do-I-get-paid" }] },
- refinery89: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Payment minimum", value: "€250 or $250", note: "a month, by region", sourceUrl: "https://refinery89.com/docs/faqs/finance/is-there-a-minimum-threshold-for-getting-paid/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: "€250 or $250, based on region", paymentMethods: [], sources: [{ label: "Payment threshold", url: "https://refinery89.com/docs/faqs/finance/is-there-a-minimum-threshold-for-getting-paid/" }, { label: "Payment timing", url: "https://refinery89.com/docs/faqs/finance/when-do-publishers-get-paid/" }, { label: "Publisher solution", url: "https://refinery89.com/publisher-ad-management-solution-refinery89/" }] },
- revcontent: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Payment minimum", value: "$250", note: "in the publisher terms; payment methods set their own too", sourceUrl: "https://help.revcontent.com/knowledge/publisher-terms" }], joining: [{ label: "Traffic", value: "No universal minimum stated", sourceUrl: "https://help.revcontent.com/knowledge/publisher-terms" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Comply with publisher terms and content policy", sourceUrl: "https://help.revcontent.com/knowledge/publisher-terms" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: "$250 in terms; payment method thresholds range from $100 ACH to $1,000 wire", paymentMethods: ["ACH", "PayPal", "Wire transfer"], sources: [{ label: "Publisher terms", url: "https://help.revcontent.com/knowledge/publisher-terms" }, { label: "Payment requirements and methods", url: "https://help.revcontent.com/knowledge/publisher-payment-requirements-methods" }] },
- setupad: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Traffic to join", value: "100,000", note: "monthly visitors or sessions; dated articles differ, so check current rules", sourceUrl: "https://setupad.com/es/blog/best-programmatic-advertising-platforms/" }, { label: "Payment minimum", value: "$100", note: "in published guidance", sourceUrl: "https://setupad.com/es/blog/best-programmatic-advertising-platforms/" }], joining: [{ label: "Traffic", value: "Not public", note: "Older official articles conflict on visitors versus sessions", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Follow publisher policy", sourceUrl: "https://setupad.com/es/blog/best-programmatic-advertising-platforms/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Maintain ads.txt", sourceUrl: "https://setupad.com/es/blog/best-programmatic-advertising-platforms/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60 in published guidance", paymentThreshold: "$100 in published guidance", paymentMethods: ["Bank transfer", "PayPal", "Payoneer", "Wise", "Revolut", "Paysera"], sources: [{ label: "Programmatic advertising guide", url: "https://setupad.com/es/blog/best-programmatic-advertising-platforms/" }, { label: "Platform comparison", url: "https://setupad.com/es/blog/ezoic-vs-adsense-vs-setupad/" }] },
- "she-media": { checkedAt: "2026-10-16", keyNumbers: [{ label: "PayPal cutoff", value: "$1,000", note: "a month, outside the US; wire is preferred above it", sourceUrl: "https://support.shemedia.com/hc/en-us/articles/35987097977627-Payment-Options-for-Publishers-Outside-the-US" }, { label: "Referral traffic", value: "20,000", note: "monthly pageviews, in referral guidance only; not a general minimum", sourceUrl: "https://www.shemedia.com/news-updates/she-media-publisher-referral-program" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Quality content", note: "The referral page describes referral eligibility, not a general applicant checklist", sourceUrl: "https://www.shemedia.com/news-updates/she-media-publisher-referral-program" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: ["PayPal", "WISE/ACH", "Wire transfer"], sources: [{ label: "International payment options", url: "https://support.shemedia.com/hc/en-us/articles/35987097977627-Payment-Options-for-Publishers-Outside-the-US" }, { label: "Publisher referral criteria", url: "https://www.shemedia.com/news-updates/she-media-publisher-referral-program" }] },
- "snack-media": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Notice to leave", value: "30 days", sourceUrl: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No hateful, pornographic, illegal, or infringing content", sourceUrl: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Share live traffic stats and install network tags", note: "Tags must be live within 14 days of the agreement date", sourceUrl: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Within 30 days after the month when Snack Media receives the advertiser funds", paymentThreshold: null, paymentMethods: [], sources: [{ label: "2025 publisher agreement terms", url: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }, { label: "Terms page", url: "https://www.snack-media.com/Ad_Network_Terms_and_Conditions_for_Publishers/" }] },
- sovrn: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Net 45", sourceUrl: "https://authcore.atlassian.net/wiki/spaces/KB/pages/2693627510846" }, { label: "Payment minimum", value: "$25", note: "$50 for wire", sourceUrl: "https://authcore.atlassian.net/wiki/spaces/KB/pages/2693627510846" }], joining: [{ label: "Traffic", value: "No minimum stated", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Operational domain, ad-system ID, and ads.txt", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 45 for Ad Exchange", paymentThreshold: "$25 standard; $50 for wire", paymentMethods: ["PayPal", "ACH", "Wire", "eCheck/local transfer", "US check"], sources: [{ label: "Account requirements", url: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Payment help", url: "https://authcore.atlassian.net/wiki/spaces/KB/pages/2693627510846" }] },
- sparteo: { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Company and services", url: "https://corporate.sparteo.com/" }, { label: "Publisher platform case study", url: "https://corporate.sparteo.com/post/w3schools-rpm-uplift-unified-monetisation-stack" }] },
- taboola: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "Within 45 days", note: "after the month ends", sourceUrl: "https://www.taboola.com/policies/publisher-revshare-terms-and-conditions-1-3-US" }], joining: [{ label: "Traffic", value: "No numeric minimum stated", sourceUrl: "https://www.taboola.com/policies/publisher-revshare-terms-and-conditions-1-3-US" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Comply with the Publisher Policy", sourceUrl: "https://pubhelp.taboola.com/hc/en-us/articles/360033751274-Taboola-Publisher-Policy" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Within 45 days after month end", paymentThreshold: null, paymentMethods: ["Payoneer"], sources: [{ label: "Publisher revenue share terms", url: "https://www.taboola.com/policies/publisher-revshare-terms-and-conditions-1-3-US" }, { label: "Publisher policy", url: "https://pubhelp.taboola.com/hc/en-us/articles/360033751274-Taboola-Publisher-Policy" }] },
- teads: { checkedAt: "2026-10-16", keyNumbers: [{ label: "Pay day", value: "30 to 60 days", note: "typical range in a company filing; contracts are not public", sourceUrl: "https://investors.teads.com/static-files/4f470000-7ee3-4919-9e4d-506e65a44af4" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Teads' company filing describes 30 to 60 days; exact agreement is not public", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Media owner partnership", url: "https://www.teads.com/media-owners" }, { label: "Company filing", url: "https://investors.teads.com/static-files/4f470000-7ee3-4919-9e4d-506e65a44af4" }] },
- "the-moneytizer": { checkedAt: "2026-10-16", keyNumbers: [{ label: "Payment minimum", value: "€50 or $50", sourceUrl: "https://www.themoneytizer.com/payment-simulator" }, { label: "Pay day", value: "About two months", note: "after the month you earn it", sourceUrl: "https://www.themoneytizer.com/payment-simulator" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Invoice is generated after month end and payment follows about two months later", paymentThreshold: "€50 or $50", paymentMethods: [], sources: [{ label: "Payment simulator", url: "https://www.themoneytizer.com/payment-simulator" }, { label: "US adtech glossary", url: "https://us.themoneytizer.com/adtech-glossary?id=16" }] },
- venatus: { checkedAt: "2026-10-16", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Official publisher platform", url: "https://www.venatus.com/" }, { label: "Publisher interest form", url: "https://info.venatus.com/en/signup" }] },
+ adapex: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day", value: "Net 60", sourceUrl: "https://adapex.io/faqs/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Ad Manager via MCM", note: "For the managed service", sourceUrl: "https://adapex.io/faqs/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher FAQ", url: "https://adapex.io/faqs/" }] },
+ aditude: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Aditude publisher guidance", url: "https://www.aditude.com/blog/the-5-questions-every-publisher-should-ask-their-monetization-partner" }, { label: "Aditude homepage", url: "https://www.aditude.com/" }, { label: "Website terms", url: "https://www.aditude.com/policies/terms" }] },
+ adnimation: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day", value: "Net 35", sourceUrl: "https://www.adnimation.com/faqs/" }], joining: [{ label: "Traffic", value: "Substantial traffic; no figure stated", note: "MAP is a separate program with no pageview minimum.", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No gambling, pornography, drugs, or similar content", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Google standing", value: "Follow relevant Google policy guidelines", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Must connect", value: "Share analytics access and connect Google Ad Manager, or have one created; install the ad code", sourceUrl: "https://www.adnimation.com/faqs/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "Revenue-share model; the standard-service percentage is not public", paymentTerms: "Net 35 after month end", paymentThreshold: null, paymentMethods: ["ACH (US bank)", "International bank wire", "PayPal by arrangement"], sources: [{ label: "Publisher FAQ", url: "https://www.adnimation.com/faqs/" }, { label: "Separate MAP program", url: "https://www.adnimation.com/map/" }, { label: "MAP terms", url: "https://www.adnimation.com/map-terms-conditions/" }] },
+ adpushup: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Revenue to join", value: "$3,000", note: "monthly ad revenue; no pageview minimum", sourceUrl: "https://www.adpushup.com/blog/best-ad-networks-for-small-publishers/" }, { label: "Payment minimum", value: "$50", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2022/04/Terms-of-Service.pdf" }, { label: "Pay day", value: "Net 45", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2022/04/Terms-of-Service.pdf" }], joining: [{ label: "Traffic", value: "No traffic minimum", sourceUrl: "https://www.adpushup.com/blog/best-ad-networks-for-small-publishers/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No illegal, pornographic, hateful, fraudulent, or infringing content; no invalid activity", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2022/04/Terms-of-Service.pdf" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install AdPushup code on approved sites", note: "AdPushup can approve or reject a site.", sourceUrl: "https://www.adpushup.com/wp-content/uploads/2022/04/Terms-of-Service.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "$3,000 a month", note: "The article states this minimum despite no pageview minimum.", sourceUrl: "https://www.adpushup.com/blog/best-ad-networks-for-small-publishers/" }], minTraffic: null, revenueShare: "Rate is set in a separate Publisher Agreement; the public terms do not set a fixed percentage", paymentTerms: "Net 45 after the month ends under the public terms", paymentThreshold: "$50 USD or equivalent", paymentMethods: ["Direct deposit", "Wire transfer", "PayPal"], sources: [{ label: "Small publisher requirements and payment summary", url: "https://www.adpushup.com/blog/best-ad-networks-for-small-publishers/" }, { label: "Publisher Terms of Service, last revised April 20, 2021", url: "https://www.adpushup.com/wp-content/uploads/2022/04/Terms-of-Service.pdf" }, { label: "Publisher onboarding", url: "https://www.adpushup.com/publisher/get-started/" }] },
+ "amazon-publisher-services": { checkedAt: "2026-10-21", keyNumbers: [{ label: "UAM fee", value: "10%", note: "taken from SSP bid prices before the auction", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Payment minimum", value: "$5", note: "UAM", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Pay day", value: "Net 60", note: "UAM", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Worldwide", note: "For Unified Ad Marketplace only", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Ad Manager", note: "For Unified Ad Marketplace only", sourceUrl: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Net 60 for UAM", paymentThreshold: "$5 for UAM", paymentMethods: [], sources: [{ label: "UAM publisher update", url: "https://aps.amazon.com/aps/wp-content/uploads/2023/01/aps_uam_update_011123-FINAL.pdf" }] },
+ "anymind-anymanager": { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "AnyManager tag for web or SDK for apps", sourceUrl: "https://anymindgroup.com/news/press-release/anymanagergames-launch/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "A fixed percentage is agreed in advance; the rate is not public", paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "AnyMind IR FAQ", url: "https://anymindgroup.com/ir/faq/" }, { label: "AnyManager overview", url: "https://anymindgroup.com/news/press-release/11388/" }, { label: "AnyManager Games launch and SDK", url: "https://anymindgroup.com/news/press-release/anymanagergames-launch/" }, { label: "AnyManager AI reporting and integration overview", url: "https://anymindgroup.com/news/press-release/anymanager-ai-reporting-agent" }] },
+ "buysellads-carbon-ads": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Base payout minimum", value: "$1", note: "some withdrawal methods have higher minimums", sourceUrl: "https://www.carbonads.net/faq" }, { label: "Typical CPM", value: "$1.20–$2.30", note: "a typical range, not guaranteed", sourceUrl: "https://www.carbonads.net/faq" }], joining: [{ label: "Traffic", value: "Average monthly pageviews are reviewed; no fixed minimum stated", sourceUrl: "https://www.carbonads.net/faq" }, { label: "Visitor location", value: "Strongest demand is for English-speaking developer and design audiences in the US, Canada, and Europe; other regions depend on demand", note: "This is a demand profile, not an exclusive country list.", sourceUrl: "https://www.carbonads.net/faq" }, { label: "Content", value: "Sites are reviewed for ad relevance and whether they are actively maintained", sourceUrl: "https://www.carbonads.net/faq" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Use the Carbon Tag or API", sourceUrl: "https://www.buysellads.com/publishers" }, { label: "Approval time", value: "5–7 business days", note: "For application review.", sourceUrl: "https://www.carbonads.net/faq" }], minTraffic: null, revenueShare: null, paymentTerms: "Monthly earnings are added to the BuySellAds account within 30 days after month end and are available to withdraw within 60 days; Open Collective runs quarterly by request", paymentThreshold: "$1 before withdrawal-method minimums: $20 PayPal, $50 check, or $500 wire transfer", paymentMethods: ["PayPal", "Check", "Wire transfer", "Open Collective (quarterly, by request)"], sources: [{ label: "Publisher FAQ", url: "https://www.carbonads.net/faq" }, { label: "Publisher application", url: "https://www.carbonads.net/join" }, { label: "Placement policy", url: "https://www.carbonads.net/placement-policy" }, { label: "Carbon API guide", url: "https://www.carbonads.net/docs" }, { label: "BuySellAds publisher page", url: "https://www.buysellads.com/publishers" }] },
+ clickio: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "100,000 to 1,000,000", note: "monthly pageviews; varies by region, and $500 monthly revenue can qualify a site below it", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Minimum earnings", value: "$500", note: "a month, after the first three months", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Pay day", value: "Net 60", note: "Net 30 can be chosen for some demand partners", sourceUrl: "https://legal.clickio.com/PublisherAgreement/" }], joining: [{ label: "Traffic", value: "100,000 to 1,000,000 pageviews by region", note: "Monthly thresholds are indicative; $500 monthly revenue for three months can qualify below them.", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Visitor location", value: "Sanctioned countries excluded", note: "Traffic thresholds vary by region.", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Content", value: "Follow AdSense policies and third-party rights rules", note: "Adult, shocking, or racially intolerant content cannot be monetized.", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Use ads.txt and an IAB-approved CMP; provide GA4 or a six-month report if needed", note: "Six months is a traffic report option when independent verification is unavailable, not a site-age rule.", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Site history", value: "Six months of traffic data if independent verification is unavailable", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Ad revenue", value: "$500 a month for three months", note: "Can qualify below the regional pageview requirement; also the ongoing account earnings minimum after three months.", sourceUrl: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }], minTraffic: null, joinSummary: "100,000 to 1,000,000 pageviews a month by region, or $500 a month in ad revenue", revenueShare: "No fixed percentage; publisher commission depends on advertiser-selected tariffs and events", paymentTerms: "Current help page lists Net 60; the publisher agreement allows Net 30 for Net30 demand partners only, or Net 60 for all available demand partners", paymentThreshold: "Depends on payment method: $100 equivalent for ACH/eCheck/SEPA, check, or PayPal; $200 wire; $10 WebMoney; GBP 100 equivalent Payoneer", paymentMethods: ["ACH", "eCheck", "SEPA/local bank transfer", "Wire transfer", "Check", "PayPal", "WebMoney", "Payoneer"], sources: [{ label: "Entry standards", url: "https://docs.clickio.com/books/clickio-entry-standards/page/clickio-entry-standards" }, { label: "Payments and billing", url: "https://docs.clickio.com/books/get-started/page/payments-billing" }, { label: "Publisher agreement", url: "https://legal.clickio.com/PublisherAgreement/" }, { label: "How to join Clickio", url: "https://docs.clickio.com/books/get-started/chapter/how-to-join-clickio" }] },
+ concert: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Concert SSP announcement", url: "https://www.voxmedia.com/2022/6/7/23157157/vox-media-concert-ssp-publisher-led-supply-side-platform-trade-desk-as-an-exclusive-launch-partner/" }, { label: "Concert advertiser terms", url: "https://admanager.concert.io/terms" }, { label: "Concert media kit", url: "https://cdn.vox-cdn.com/uploads/chorus_asset/file/22462899/Media_Kit_April_2021pdf.pdf" }] },
+ ethicalads: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Your share", value: "70%", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Payment minimum", value: "$50", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }, { label: "Pay day", value: "Monthly", note: "target by the 15th", sourceUrl: "https://www.ethicalads.io/publisher-policy/" }], joining: [{ label: "Traffic", value: "50,000 pageviews a month", note: "Exceptions may be considered for high-quality or growing sites", sourceUrl: "https://www.ethicalads.io/publishers/faq/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Developer-focused sites that meet the publisher policy", note: "The policy sets ad placement and click-through requirements", sourceUrl: "https://www.ethicalads.io/publishers/faq/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install the EthicalAds ad client after applying", sourceUrl: "https://www.ethicalads.io/publisher-guide/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 50000, unit: "pageviews" }, revenueShare: "70%", paymentTerms: "Monthly; target payment date is the 15th", paymentThreshold: "$50", paymentMethods: ["Stripe Connect / bank transfer", "PayPal", "OpenCollective", "GitHub Sponsors"], sources: [{ label: "Publisher FAQ", url: "https://www.ethicalads.io/publishers/faq/" }, { label: "Publisher policy", url: "https://www.ethicalads.io/publisher-policy/" }, { label: "Publisher guide", url: "https://www.ethicalads.io/publisher-guide/" }, { label: "Terms of service", url: "https://www.ethicalads.io/terms-of-service/" }] },
+ ezoic: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Users to join", value: "250,000", note: "monthly active users for new sites", sourceUrl: "https://support.ezoic.com/kb/article/getting-started-ezoics-requirements?id=getting-started-ezoics-requirements&lang=es-ES" }, { label: "Your share", value: "82%", note: "at least, of net display-ad revenue", sourceUrl: "https://www.ezoic.com/terms" }, { label: "Payment minimum", value: "$20", sourceUrl: "https://www.ezoic.com/terms" }], joining: [{ label: "Traffic", value: "250,000+ monthly active users for new sites", note: "Smaller sites may apply to the limited Incubator; sites monetizing before February 19, 2026 can be grandfathered if they keep using Ezoic.", sourceUrl: "https://support.ezoic.com/kb/article/getting-started-ezoics-requirements?id=getting-started-ezoics-requirements&lang=es-ES" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original content in an AdSense-supported language; follow Google publisher policies", sourceUrl: "https://support.ezoic.com/kb/article/getting-started-ezoics-requirements?id=getting-started-ezoics-requirements&lang=es-ES" }, { label: "Google standing", value: "Comply with Google and AdSense policies; AdSense approval is not required for most sites", sourceUrl: "https://support.ezoic.com/kb/article/getting-started-ezoics-requirements?id=getting-started-ezoics-requirements&lang=es-ES" }, { label: "Must connect", value: "Connect Google Analytics for traffic verification and Google MCM; integrate JavaScript", sourceUrl: "https://support.ezoic.com/kb/article/ezoic-site-requirements-for-monetization" }, { label: "Approval time", value: "Ezoic review usually finishes within 10 days; Google MCM review can take up to 18 days", sourceUrl: "https://support.ezoic.com/kb/article/ezoic-site-requirements-for-monetization" }], minTraffic: { amount: 250000, unit: "visitors", label: "250,000 monthly active users" }, revenueShare: "At least 82% of net display-ad revenue under published Terms, unless another written agreement applies", paymentTerms: "About 35 days after Ezoic receives advertiser payment under the Terms; payment help describes Net 30 by default and optional Net 60/90 schedules", paymentThreshold: "$20", paymentMethods: ["Wise bank transfer", "PayPal", "Payoneer", "Check"], sources: [{ label: "Current eligibility requirements", url: "https://support.ezoic.com/kb/article/getting-started-ezoics-requirements?id=getting-started-ezoics-requirements&lang=es-ES" }, { label: "Site requirements and review timing", url: "https://support.ezoic.com/kb/article/ezoic-site-requirements-for-monetization" }, { label: "Terms", url: "https://www.ezoic.com/terms" }, { label: "Payment help", url: "https://support.ezoic.com/kb/article/ezoic-payments?lang=en-US" }, { label: "Incubator", url: "https://support.ezoic.com/kb/article/ezoic-incubator-program" }] },
+ freestar: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Typical traffic", value: "1,000,000", note: "monthly pageviews; Freestar takes all sizes but says it typically needs this", sourceUrl: "https://freestar.com/contact-us/" }, { label: "From top markets", value: "50%", note: "of traffic from the US, UK, Canada, New Zealand, or Australia", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }], joining: [{ label: "Traffic", value: "Typically at least 1,000,000 pageviews", note: "Monthly; the contact page says Freestar accepts all sizes, so this is typical rather than an absolute cutoff.", sourceUrl: "https://freestar.com/contact-us/" }, { label: "Visitor location", value: "At least 50% from the US, UK, Canada, New Zealand, or Australia", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Content", value: "Original, human-focused, mostly long-form, and brand-safe", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Google standing", value: "Good standing with all major ad providers", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Must connect", value: "Provide GA4 access, traffic and revenue history, and demand-partner status", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }, { label: "Approval time", value: "About 3 to 6 weeks from kickoff to launch", note: "This is onboarding-to-launch timing, not review time alone.", sourceUrl: "https://freestar.com/contact-us/" }, { label: "Traffic source", value: "At least 50% from organic audiences", sourceUrl: "https://freestar.com/publisher-quality-requirements/" }], minTraffic: { amount: 1000000, unit: "pageviews", label: "Typically 1,000,000 pageviews a month" }, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher quality requirements", url: "https://freestar.com/publisher-quality-requirements/" }, { label: "Publisher contact and onboarding", url: "https://freestar.com/contact-us/" }] },
+ "geniee-ssp": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Payment minimum", value: "$100", note: "$200 for wire transfer", sourceUrl: "https://s.geniee.jp/aladdin/resources/GenieeInternational/terms_geniee_en.pdf" }, { label: "Pay day", value: "End of month 2", note: "after earnings are calculated, once the advertiser pays", sourceUrl: "https://s.geniee.jp/aladdin/resources/GenieeInternational/terms_geniee_en.pdf" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No false, obscene, infringing, or illegal content", sourceUrl: "https://s.geniee.jp/aladdin/resources/GenieeInternational/terms_geniee_en.pdf" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install Geniee's tags and keep them in place", sourceUrl: "https://s.geniee.jp/aladdin/resources/GenieeInternational/terms_geniee_en.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Application", value: "Submit an application form", sourceUrl: "https://admin.genieessp.com/app/signup/en_US" }], minTraffic: null, revenueShare: null, paymentTerms: "Calculated the following month; transferred by the end of the second month after calculation if the advertiser pays", paymentThreshold: "$100 for PayPal or Payoneer; $200 for wire transfer", paymentMethods: ["PayPal", "Payoneer", "Wire transfer"], sources: [{ label: "Publisher terms of use", url: "https://s.geniee.jp/aladdin/resources/GenieeInternational/terms_geniee_en.pdf" }, { label: "Publisher signup form", url: "https://admin.genieessp.com/app/signup/en_US" }] },
+ "google-adsense": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Your share", value: "80%", note: "after the advertiser platform fee; about 68% with Google Ads demand", sourceUrl: "https://support.google.com/adsense/answer/180195?hl=en" }, { label: "Payment minimum", value: "$100", note: "in US dollars", sourceUrl: "https://support.google.com/adsense/answer/1709871?hl=en" }, { label: "Pay days", value: "21st to 26th", note: "of each month", sourceUrl: "https://support.google.com/adsense/answer/7164701?hl=en" }], joining: [{ label: "Traffic", value: "No minimum stated", sourceUrl: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Visitor location", value: "Sign-up is available in listed countries", sourceUrl: "https://support.google.com/adsense/answer/13402307?hl=en" }, { label: "Content", value: "Original, high-quality, policy-compliant content", sourceUrl: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Google standing", value: "No account termination for invalid traffic or policy violations", sourceUrl: "https://support.google.com/adsense/answer/81904?hl=en" }, { label: "Must connect", value: "Access to the site HTML", note: "Add the verification code or ad code and request a site review", sourceUrl: "https://support.google.com/adsense/answer/7584263?hl=en" }, { label: "Approval time", value: "Usually a few days; sometimes 2 to 4 weeks", sourceUrl: "https://support.google.com/adsense/answer/7402256?hl=en" }], minTraffic: { amount: 0, unit: "pageviews" }, revenueShare: "80% after the advertiser platform fee for AdSense for Content", paymentTerms: "Monthly; payments are issued between the 21st and 26th when the balance reaches threshold and there are no holds", paymentThreshold: "$100 USD, with equivalent thresholds by account currency", paymentMethods: ["Check", "EFT", "SEPA", "Wire transfer", "PayPal Hyperwallet where available"], sources: [{ label: "Revenue share", url: "https://support.google.com/adsense/answer/180195?hl=en" }, { label: "Payment threshold", url: "https://support.google.com/adsense/answer/1709871?hl=en" }, { label: "Payment schedule", url: "https://support.google.com/adsense/answer/7164701?hl=en" }, { label: "Eligibility", url: "https://support.google.com/adsense/answer/9724?hl=en" }, { label: "Sign-up countries", url: "https://support.google.com/adsense/answer/13402307?hl=en" }, { label: "Account restrictions after invalid traffic or policy termination", url: "https://support.google.com/adsense/answer/81904?hl=en" }, { label: "Site review timing", url: "https://support.google.com/adsense/answer/7402256?hl=en" }, { label: "Site verification and review steps", url: "https://support.google.com/adsense/answer/7584263?hl=en" }, { label: "Payment methods", url: "https://support.google.com/adsense/answer/1714397?hl=en-EN" }] },
+ infolinks: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Your share", value: "70%", note: "for In-Text ads under the published agreement", sourceUrl: "https://sites0001.infolinks.com/service-agreement" }, { label: "Pay day", value: "45 working days", note: "after month end, if the payment threshold is met", sourceUrl: "https://sites0001.infolinks.com/service-agreement" }, { label: "Payment minimum", value: "$50–$100", note: "depends on payment method", sourceUrl: "https://sites0001.infolinks.com/support/payments/what-is-the-infolinks-payment-threshold" }], joining: [{ label: "Traffic", value: "No minimum pageviews or visitors", sourceUrl: "https://sites0001.infolinks.com/support/quality/what-are-the-eligibility-criteria-for-my-site-to-qualify-with-infolinks" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No adult, illegal, hateful, or infringing content", sourceUrl: "https://sites0001.infolinks.com/service-agreement" }, { label: "Google standing", value: "Publisher or related entities must not have been terminated by another monetization platform in the prior 24 months", note: "The agreement names Google AdSense as an example.", sourceUrl: "https://sites0001.infolinks.com/service-agreement" }, { label: "Must connect", value: "Install Infolinks JavaScript on approved sites", sourceUrl: "https://sites0001.infolinks.com/support/integration/how-do-i-integrate-infolinks-into-my-website" }, { label: "Approval time", value: "Within 48 hours", sourceUrl: "https://sites0001.infolinks.com/support/account/how-do-i-sign-up-as-an-infolinks-publisher" }], minTraffic: { amount: 0, unit: "pageviews" }, revenueShare: "70% for In-Text ads under the published agreement; rates for other formats vary", paymentTerms: "45 working days after month end when the selected payment threshold is met, under the published agreement", paymentThreshold: "$50 for PayPal, eCheck, ACH, or Payoneer; $100 for bank wire or Western Union", paymentMethods: ["PayPal", "Bank wire", "eCheck", "ACH", "Payoneer", "Western Union"], sources: [{ label: "Publisher eligibility", url: "https://sites0001.infolinks.com/support/quality/what-are-the-eligibility-criteria-for-my-site-to-qualify-with-infolinks" }, { label: "Service agreement, last updated 2015", url: "https://sites0001.infolinks.com/service-agreement" }, { label: "Publisher sign-up and review", url: "https://sites0001.infolinks.com/support/account/how-do-i-sign-up-as-an-infolinks-publisher" }, { label: "Integration", url: "https://sites0001.infolinks.com/support/integration/how-do-i-integrate-infolinks-into-my-website" }, { label: "Payment options", url: "https://sites0001.infolinks.com/support/payments/what-are-my-payment-options" }, { label: "Payment thresholds", url: "https://sites0001.infolinks.com/support/payments/what-is-the-infolinks-payment-threshold" }] },
+ "journey-by-mediavine": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "1,000", note: "premium sessions a month, per the founder's update", sourceUrl: "https://www.linkedin.com/posts/hochberger_two-years-ago-we-launched-journey-by-mediavine-activity-7491505513915027456-JBHZ" }, { label: "Your share", value: "70%", sourceUrl: "https://www.journeymv.com/getting-started-with-journey-by-mediavine/" }, { label: "Pay day", value: "Net 65", sourceUrl: "https://www.journeymv.com/getting-started-with-journey-by-mediavine/" }], joining: [{ label: "Traffic", value: "1,000 premium sessions a month", sourceUrl: "https://www.linkedin.com/posts/hochberger_two-years-ago-we-launched-journey-by-mediavine-activity-7491505513915027456-JBHZ" }, { label: "Visitor location", value: "Worldwide where Mediavine does business", sourceUrl: "https://get.journeymv.com/start-your-journey-1/" }, { label: "Content", value: "Original, engaging, human-written, brand-safe, regularly updated content", sourceUrl: "https://www.journeymv.com/affiliates-faq/" }, { label: "Google standing", value: "No active AdSense or Ad Exchange policy issues", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine/" }, { label: "Must connect", value: "Install and run Grow for at least 30 days", note: "GA4 is optional.", sourceUrl: "https://www.journeymv.com/getting-started-with-journey-by-mediavine/" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Site history", value: "About four months of domain history expected", note: "Journey says this is expected because of ad-partner requirements, not a confirmed Journey rule.", sourceUrl: "https://www.journeymv.com/getting-started-with-journey-by-mediavine/" }], minTraffic: { amount: 1000, unit: "sessions", label: "1,000 premium sessions a month" }, revenueShare: "70% revenue share for Journey", paymentTerms: "Net 65", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Mediavine approval requirements, including Journey", url: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine/" }, { label: "Journey getting started: Grow, domain history, share and payment schedule", url: "https://www.journeymv.com/getting-started-with-journey-by-mediavine/" }, { label: "Journey publisher requirements", url: "https://www.journeymv.com/affiliates-faq/" }, { label: "Journey publisher page and supported regions", url: "https://get.journeymv.com/start-your-journey-1/" }, { label: "Mediavine founder update on the 1,000 premium-session bar", url: "https://www.linkedin.com/posts/hochberger_two-years-ago-we-launched-journey-by-mediavine-activity-7491505513915027456-JBHZ" }] },
+ "media-net": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day", value: "Net 30", sourceUrl: "https://www.media.net/legal/" }], joining: [{ label: "Traffic", value: "Mostly organic traffic", sourceUrl: "https://www.media.net/legal/inventorypolicies/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Original content; prohibited topics are excluded", sourceUrl: "https://www.media.net/legal/inventorypolicies/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Publish an authorized ads.txt or app-ads.txt file", sourceUrl: "https://www.media.net/legal/inventorypolicies/" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Prior provider history", value: "No prior suspension or termination by another monetization provider", sourceUrl: "https://www.media.net/legal/", note: "The agreement also requires disclosure of specified prior traffic or policy suspensions" }], minTraffic: null, revenueShare: null, paymentTerms: "Net 30; monthly payments based on collected click-through revenue less commissions and costs", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher Agreement", url: "https://www.media.net/legal/" }, { label: "Inventory policies", url: "https://www.media.net/legal/inventorypolicies/" }] },
+ mediavine: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Revenue to join", value: "$5,000", note: "in annual ad revenue", sourceUrl: "https://www.mediavine.com/application-requirements/" }, { label: "Your share", value: "75% to 90%", note: "by 2026 program tier; older contracts may differ", sourceUrl: "https://help.mediavine.com/revenue-share" }, { label: "Pay day", value: "Net 65", sourceUrl: "https://help.mediavine.com/when-am-i-getting-paid-0" }], joining: [{ label: "Traffic", value: "Annual revenue, not a fixed traffic minimum", note: "Official starts at $5,000 yearly ad revenue; Journey is separate at 1,000 Tier 1 sessions in 30 days", sourceUrl: "https://www.mediavine.com/programs/" }, { label: "Visitor location", value: "No fixed mix; traffic origin is reviewed", note: "Mediavine evaluates traffic location, sources, and demographics", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Content", value: "Original, audience-first content with clean, human, brand-safe traffic", sourceUrl: "https://www.mediavine.com/application-requirements/" }, { label: "Google standing", value: "Good standing with AdSense and Ad Exchange", note: "No active policy violations or account issues", sourceUrl: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "Must connect", value: "Provide read-only Google Analytics access during review", sourceUrl: "https://prod.mediavine.com/blog/mediavine-application-process-faq/" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "$5,000 a year for Official", note: "The 2026 publisher path sets program tiers by company-wide revenue across sites", sourceUrl: "https://www.mediavine.com/programs/" }], minTraffic: null, revenueShare: "For new sites under the 2026 programs: 75% Official, 80% Select, 85% Signature, and 90% Premiere or Premiere Plus; legacy sites may have different rates", paymentTerms: "Net 65 from month end; processed on the first business day", paymentThreshold: "$100 for most methods; $200 for eCheck or local bank transfer", paymentMethods: ["PayPal", "Domestic ACH", "Wise", "US wire", "eCheck / local bank transfer", "International wire"], sources: [{ label: "Mediavine application requirements", url: "https://www.mediavine.com/application-requirements/" }, { label: "Approval criteria, including Journey", url: "https://help.mediavine.com/what-does-it-take-to-get-approved-by-mediavine" }, { label: "2026 programs and revenue eligibility", url: "https://www.mediavine.com/programs/" }, { label: "Revenue share by program", url: "https://help.mediavine.com/revenue-share" }, { label: "Payment timing", url: "https://help.mediavine.com/when-am-i-getting-paid-0" }, { label: "Payment methods and minimums", url: "https://help.mediavine.com/mediavine-payment-methods" }, { label: "Application and Google Analytics access", url: "https://prod.mediavine.com/blog/mediavine-application-process-faq/" }, { label: "Google MCM onboarding", url: "https://help.mediavine.com/google-mcm-what-you-need-to-know" }] },
+ mgid: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "3,000", note: "unique visitors a day, about 90,000 a month", sourceUrl: "https://help.mgid.com/publishers-general-information" }, { label: "Your share", value: "65%", note: "in a published Brazil offer; current order terms may differ", sourceUrl: "https://pr.mgid.com/monetize" }, { label: "Payment minimums", value: "$50 to $1,000", note: "depends on payment method", sourceUrl: "https://pr.mgid.com/monetize" }], joining: [{ label: "Traffic", value: "At least 3,000 unique visitors daily (90,000+ monthly)", sourceUrl: "https://help.mgid.com/publishers-general-information" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No adult, illegal, hateful, violent, or infringing content", sourceUrl: "https://www.mgid.com/services/publishers-tos" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install MGID ad-unit code using the Dashboard instructions", sourceUrl: "https://www.mgid.com/services/publishers-tos" }, { label: "Approval time", value: "Approval or rejection email within 24 hours; weekend reviews move to the next business day", sourceUrl: "https://help.mgid.com/publishers-general-information" }], minTraffic: { amount: 90000, unit: "visitors", label: "3,000 unique visitors a day" }, revenueShare: "65% in the published Brazil offer; the current Insertion Order controls the publisher's rate", paymentTerms: "Net 30 post-payment in the published Brazil offer; the current Insertion Order controls", paymentThreshold: "Method-specific in the published offer: $50 Paymaster24; $100 PayPal or Tipalti; $1,000 ACH or international bank transfer", paymentMethods: ["Paymaster24", "PayPal", "Tipalti bank transfer", "ACH bank transfer", "International bank transfer"], sources: [{ label: "Current publisher information", url: "https://help.mgid.com/publishers-general-information" }, { label: "Publisher terms, updated July 2026", url: "https://www.mgid.com/services/publishers-tos" }, { label: "Published Brazil publisher offer", url: "https://pr.mgid.com/monetize" }, { label: "Global publisher coverage", url: "https://www.mgid.com/publishers" }, { label: "Older publisher requirements, last updated 2020", url: "https://www.mgid.com/services/publisher-requirements" }] },
+ "monetizemore-pubguru": { checkedAt: "2026-10-21", keyNumbers: [{ label: "To join PubGuru Premium", value: "$5,000", note: "monthly ad revenue or 2 million monthly pageviews", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }], joining: [{ label: "Traffic", value: "2,000,000 pageviews", note: "Monthly; alternative to the $5,000 revenue criterion.", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Flexible setup through the publisher’s Google Ad Manager and demand partners", note: "Product setup detail, not a separate eligibility rule.", sourceUrl: "https://www.monetizemore.com/blog/header-bidding-platforms/" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Ad revenue", value: "$5,000 a month", note: "Alternative to 2,000,000 monthly pageviews.", sourceUrl: "https://www.monetizemore.com/solutions/pubguru-premium/" }], minTraffic: null, joinSummary: "$5,000 ad revenue or 2 million pageviews a month", revenueShare: "Performance-based share customized per publisher; PubGuru Premium rate is not published", paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "PubGuru Premium requirements and features", url: "https://www.monetizemore.com/solutions/pubguru-premium/" }, { label: "PubGuru and header-bidding setup", url: "https://www.monetizemore.com/blog/header-bidding-platforms/" }, { label: "MonetizeMore revenue model", url: "https://www.monetizemore.com/blog/ezoic-vs-adsense-vs-monetizemore/" }, { label: "MonetizeMore FAQ", url: "https://www.monetizemore.com/frequently-asked-questions/" }] },
+ monumetric: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "10,000", note: "monthly pageviews", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Pay day", value: "Net 60", sourceUrl: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }, { label: "Payment minimum", value: "$10", sourceUrl: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }], joining: [{ label: "Traffic", value: "At least 10,000 pageviews", note: "Monthly", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Visitor location", value: "At least 50% from the US, UK, Canada, or Australia", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Content", value: "English; no pornography, drugs, hate speech, or copyrighted content", sourceUrl: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Ad Manager through MCM", sourceUrl: "https://www.monumetric.com/what-googles-switch-to-mcm-means-for-publishers/" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Propel setup", value: "WordPress or Blogger, six ad slots, and a $99 implementation fee", note: "Propel only", sourceUrl: "https://www.monumetric.com/requirements-for-the-propel-program/" }], minTraffic: { amount: 10000, unit: "pageviews" }, revenueShare: null, paymentTerms: "Net 60; paid monthly within the first ten business days", paymentThreshold: "$10; balance rolls forward below this amount", paymentMethods: ["US direct deposit", "International PayPal"], sources: [{ label: "Eligibility requirements", url: "https://www.monumetric.com/what-are-the-requirements-to-work-with-monumetric/" }, { label: "Propel program requirements", url: "https://www.monumetric.com/requirements-for-the-propel-program/" }, { label: "Google MCM setup", url: "https://www.monumetric.com/what-googles-switch-to-mcm-means-for-publishers/" }, { label: "Payment terms", url: "https://www.monumetric.com/payment-terms-and-how-you-are-paid/" }] },
+ "newor-media": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic for Catapult", value: "60,000", note: "US pageviews a month; Catapult only, not a general minimum", sourceUrl: "https://newormedia.com/programs" }, { label: "Traffic for Premier", value: "420,000", note: "US pageviews a month; Premier only, not a general minimum", sourceUrl: "https://newormedia.com/programs" }, { label: "Payment terms", value: "Net 30 / Net 45", note: "FAQ says Net 30; platform agreement says Net 45", sourceUrl: "https://newormedia.com/faqs/what-are-your-payment-terms" }], joining: [{ label: "Traffic", value: "No minimum for Elevate", note: "Catapult: 60,000 US pageviews; Premier: 420,000 US pageviews monthly", sourceUrl: "https://newormedia.com/programs" }, { label: "Visitor location", value: "Traffic origin is reviewed; no fixed country share stated", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Content", value: "English site with navigation; follow Google ad policies", note: "Elevate also requires at least two ad units per page", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Google standing", value: "Follow Google ad policies", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Must connect", value: "Google Ad Manager account", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Approval time", value: "Usually responds within 24 to 48 hours", note: "This is the stated response window, not a guaranteed approval time", sourceUrl: "https://newormedia.com/elevatefaqs" }, { label: "Exclusivity", value: "Required", note: "Newor Media says all publishers must be exclusive", sourceUrl: "https://newormedia.com/elevatefaqs" }], minTraffic: { amount: 0, unit: "pageviews" }, revenueShare: null, paymentTerms: "Net 30 in the public FAQ; Net 45 in the platform agreement", paymentThreshold: null, paymentMethods: ["PayPal", "Payoneer", "Direct wire transfer"], sources: [{ label: "Programs", url: "https://newormedia.com/programs" }, { label: "Elevate FAQ", url: "https://newormedia.com/elevatefaqs" }, { label: "Platform agreement", url: "https://newormedia.com/node/296" }, { label: "Payment terms FAQ", url: "https://newormedia.com/faqs/what-are-your-payment-terms" }, { label: "Payment methods FAQ", url: "https://newormedia.com/faqs/how-do-you-make-payments" }] },
+ nitropay: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day", value: "Net 7", sourceUrl: "https://nitropay.com/docs/" }, { label: "Payout minimum", value: "None", note: "above transaction fees", sourceUrl: "https://nitropay.com/docs/" }, { label: "Go-live time", value: "5–7 business days", note: "after your site is accepted", sourceUrl: "https://nitropay.com/docs/" }], joining: [{ label: "Traffic", value: "Traffic amount is reviewed; no numeric minimum is published", sourceUrl: "https://nitropay.com/docs/" }, { label: "Visitor location", value: "Traffic geography is reviewed; accepted regions are not listed", sourceUrl: "https://nitropay.com/docs/" }, { label: "Content", value: "Site content and niche are reviewed; guidelines bar adult, illegal, violent, or infringing content", sourceUrl: "https://blog.nitropay.com/guidelines/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install Nitro ad tags and provide a Google Ad Manager network code for Google MCM; GA4 access can speed review", sourceUrl: "https://nitropay.com/docs/" }, { label: "Approval time", value: "Average 5–7 business days after quality acceptance, before enough SSP coverage to go live", sourceUrl: "https://nitropay.com/docs/" }], minTraffic: null, revenueShare: null, paymentTerms: "Net 7; paid seven days after the start of each month", paymentThreshold: "No fixed minimum; earnings must exceed the transaction fee", paymentMethods: ["ACH (US)", "EFT (Canada)", "FPS (UK)", "NPP (Australia)", "BECS (New Zealand)", "FPSHK (Hong Kong)", "SEPA (Europe)", "IACH", "SWIFT wire"], sources: [{ label: "Nitro Docs Archive: approval, onboarding, and payments", url: "https://nitropay.com/docs/" }, { label: "Publisher Guidelines", url: "https://blog.nitropay.com/guidelines/" }] },
+ "opti-digital": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day, Managed Inventory", value: "Net 45", sourceUrl: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }, { label: "Pay day, Managed Account", value: "Net 60", note: "for Opti demand; Google pays its own revenue on a 25-day cycle", sourceUrl: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Demand Hub needs CMP, ads.txt, and bidder setup", note: "This is for the Demand Hub product; no general publisher sign-up requirement is stated.", sourceUrl: "https://knowledge-base.optidigital.com/knowledge/getting-started-with-demand-hub" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "Share of gross programmatic revenue; percentage not public", paymentTerms: "Net 45 for Managed Inventory; Net 60 for Opti demand under Managed Account; Google pays direct on its 25-day cycle", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Payment terms by setup", url: "https://knowledge-base.optidigital.com/knowledge/understanding-your-payment-terms" }, { label: "Revenue-share and invoice flow", url: "https://knowledge-base.optidigital.com/knowledge/how-is-the-invoicing-working-at-opti-digital-when-will-i-get-paid" }, { label: "Demand Hub publisher integration", url: "https://knowledge-base.optidigital.com/knowledge/getting-started-with-demand-hub" }, { label: "Opti Digital publisher referral page (referral terms only)", url: "https://optidigital.com/refer-a-publisher/" }] },
+ playwire: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "500,000", note: "monthly website pageviews; apps need 1,000 daily active users", sourceUrl: "https://www.playwire.com/faq" }, { label: "Your share", value: "50% / 75%", note: "of net direct-sales / indirect-sales revenue", sourceUrl: "https://www.playwire.com/terms-of-service" }, { label: "Pay day", value: "Net 60", sourceUrl: "https://www.playwire.com/terms-of-service" }], joining: [{ label: "Traffic", value: "500,000 monthly pageviews or 1,000 daily active app users", note: "The separate qualification guide suggests applying at 100,000 pageviews or 10,000 app DAUs for full ROI", sourceUrl: "https://www.playwire.com/faq" }, { label: "Visitor location", value: "Good footprint in English-speaking countries", note: "At least 20% US traffic is associated with higher average revenue, not stated as an eligibility minimum", sourceUrl: "https://www.playwire.com/faq" }, { label: "Content", value: "Unique, original content; IVT rating no higher than 7%", sourceUrl: "https://www.playwire.com/faq" }, { label: "Google standing", value: "Not blacklisted by Google or other major ad providers", sourceUrl: "https://www.playwire.com/faq" }, { label: "Must connect", value: "Implement the Playwire SDK", note: "Required to access Playwire demand", sourceUrl: "https://www.playwire.com/faq" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 500000, unit: "pageviews" }, revenueShare: "50% of net direct-sales revenue; 75% of net indirect-sales revenue", paymentTerms: "Net 60 after month-end; paid in US dollars", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher FAQ", url: "https://www.playwire.com/faq" }, { label: "Qualification criteria", url: "https://www.playwire.com/qualification-criteria" }, { label: "Publisher terms of service", url: "https://www.playwire.com/terms-of-service" }] },
+ pubfuture: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "100,000", note: "monthly pageviews, from PubFuture's 2025 case study", sourceUrl: "https://blog.pubfuture.com/the-secret-to-400-more-revenue-for-h5-game-sites-pubfutures-winning-formula/1007/" }, { label: "Pay day", value: "Net 30", sourceUrl: "https://pubfuture.com/" }, { label: "Payment minimum", value: "$50", sourceUrl: "https://pubfuture.com/" }], joining: [{ label: "Traffic", value: "100,000 pageviews a month", note: "A 2025 PubFuture case study calls this its minimum threshold; no current criteria page was found", sourceUrl: "https://blog.pubfuture.com/the-secret-to-400-more-revenue-for-h5-game-sites-pubfutures-winning-formula/1007/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: { amount: 100000, unit: "pageviews" }, revenueShare: null, paymentTerms: "Net 30", paymentThreshold: "$50", paymentMethods: ["PayPal", "Payoneer", "Bank transfer", "Bitcoin"], sources: [{ label: "Publisher FAQ and payment terms", url: "https://pubfuture.com/" }, { label: "Publisher case study stating the minimum threshold", url: "https://blog.pubfuture.com/the-secret-to-400-more-revenue-for-h5-game-sites-pubfutures-winning-formula/1007/" }, { label: "Publisher contact form", url: "https://pubfuture.com/contact" }, { label: "Publisher onboarding and ads.txt article", url: "https://blog.pubfuture.com/ads-txt-and-ad-revenue-what-every-publisher-should-know/1236/" }] },
+ pubgalaxy: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Azerion announcement unifying publisher supply under Improve Digital", url: "https://www.azerion.com/azerion-unifies-its-publisher-supply-business-under-improve-digital-launching-a-full-circle-solution-for-publishers/" }, { label: "Current Improve Digital publisher offering", url: "https://improvedigital.com/" }, { label: "PubGalaxy official LinkedIn transition update", url: "https://gl.linkedin.com/company/pubgalaxy" }] },
+ publift: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Revenue to join", value: "More than $2,000", note: "monthly ad revenue, in USD", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Revenue split", value: "80/20", note: "in Publift's 2026 comparison; confirm in your order", sourceUrl: "https://www.publift.com/blog/best-mediavine-alternatives" }, { label: "Payment minimum", value: "$200", sourceUrl: "https://www.publift.com/blog/the-best-cpm-ad-network-for-publishers" }], joining: [{ label: "Traffic", value: "500,000 pageviews is a secondary signal", note: "Monthly; revenue is the main qualifying metric.", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Visitor location", value: "Best fit: majority of traffic from the Americas, Europe, or Australia/New Zealand", note: "Publift says it works best with this mix; it does not state a strict geographic cutoff.", sourceUrl: "https://www.publift.com/how-it-works" }, { label: "Content", value: "Useful, original, appropriate, and brand-safe content", sourceUrl: "https://www.publift.com/blog/publift-requirements" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Ad tags provided within five days", note: "The guide does not separate review time from the ad-tag delivery window.", sourceUrl: "https://www.publift.com/blog/the-best-cpm-ad-network-for-publishers" }, { label: "Ad revenue", value: "More than $2,000 a month", note: "Primary qualifying metric, in USD.", sourceUrl: "https://www.publift.com/blog/publift-requirements" }], minTraffic: null, revenueShare: "80/20 model according to Publift’s 2026 comparison; confirm in the order", paymentTerms: "Google revenue: Net 30; other ad-network revenue: Net 90", paymentThreshold: "$200 USD", paymentMethods: ["Direct bank transfer"], sources: [{ label: "Publift requirements", url: "https://www.publift.com/blog/publift-requirements" }, { label: "How it works and publisher fit", url: "https://www.publift.com/how-it-works" }, { label: "2026 Mediavine alternatives comparison and revenue split", url: "https://www.publift.com/blog/best-mediavine-alternatives" }, { label: "2026 CPM network payment and tag timing comparison", url: "https://www.publift.com/blog/the-best-cpm-ad-network-for-publishers" }, { label: "2026 payment comparison", url: "https://www.publift.com/blog/ezoic-vs-adsense-vs-publift" }] },
+ publir: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Programmatic share", value: "85%", note: "publisher share; Publir retains 15%, before applicable service costs", sourceUrl: "https://publir.com/service_agreement" }, { label: "Custom ad share", value: "50/50", note: "publisher and Publir; Net 60", sourceUrl: "https://publir.com/service_agreement" }, { label: "Pro fee", value: "15%", note: "separate from custom ad sales", sourceUrl: "https://publir.com/app/pricing" }], joining: [{ label: "Traffic", value: "No traffic limit", sourceUrl: "https://publir.com/app/pricing" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install Publir's software and ad tags", sourceUrl: "https://publir.com/service_agreement" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Exclusivity", value: "Non-exclusive service agreement", sourceUrl: "https://publir.com/service_agreement" }, { label: "Notice", value: "Either party may terminate with 30 days’ notice", sourceUrl: "https://publir.com/service_agreement" }], minTraffic: { amount: 0, unit: "pageviews" }, revenueShare: "Programmatic and subscriptions: 85% to publisher before service costs; custom ads: 50/50; crowdfunding: Publir retains 15%", paymentTerms: "Programmatic and custom ads: at least monthly on Net 60; subscriptions: paid at least monthly", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Pricing", url: "https://publir.com/app/pricing" }, { label: "Service agreement", url: "https://publir.com/service_agreement" }] },
+ "publisher-collective": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Revenue benchmark", value: "About €300", note: "daily ad revenue; a guide, not the main rule", sourceUrl: "https://www.publisher-collective.com/faq" }, { label: "Payment minimum", value: "€500", sourceUrl: "https://www.publisher-collective.com/partners-terms-conditions" }], joining: [{ label: "Traffic", value: "About €300 daily revenue; 3 million monthly pageviews outside core genres", note: "The FAQ says lower-revenue publishers may still be assessed for significant growth or high quality; this is not a universal floor", sourceUrl: "https://www.publisher-collective.com/faq" }, { label: "Visitor location", value: "Works with publishers globally", sourceUrl: "https://www.publisher-collective.com/faq" }, { label: "Content", value: "Unique, high-quality content and reputable traffic", note: "No bots or fraudulent traffic; partner terms also prohibit specified content", sourceUrl: "https://www.publisher-collective.com/faq" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Add Publisher Collective JavaScript tags to the site", sourceUrl: "https://www.publisher-collective.com/faq" }, { label: "Approval time", value: "Not public", note: "The FAQ gives 10 to 14 days for onboarding setup, not application approval", sourceUrl: "https://www.publisher-collective.com/faq" }], minTraffic: null, revenueShare: "Set individually in the Advertising Representation Agreement", paymentTerms: "Paid after the advertiser pays; the partner terms set no fixed interval", paymentThreshold: "€500", paymentMethods: ["Bank transfer; GBP, EUR, or USD"], sources: [{ label: "Publisher FAQ and current eligibility", url: "https://www.publisher-collective.com/faq" }, { label: "Partner terms", url: "https://www.publisher-collective.com/partners-terms-conditions" }] },
+ pubnation: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Aimed at elite, top-earning publishers; no numeric threshold stated", sourceUrl: "https://www.pubnation.com/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Mentions gaming, sports, tech, entertainment, and other genres", sourceUrl: "https://www.pubnation.com/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Official publisher homepage", url: "https://www.pubnation.com/" }] },
+ pubpower: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Typical traffic", value: "100,000", note: "monthly visitors, as a rough guide", sourceUrl: "https://help.pubpower.io/article/website-requirements" }, { label: "Pay day", value: "Net 0 or Net 30", note: "Net 0 above $3,000 a month in revenue", sourceUrl: "https://help.pubpower.io/article/payment-methods-terms" }, { label: "Payoneer minimum", value: "$50", sourceUrl: "https://help.pubpower.io/article/payment-methods-terms" }], joining: [{ label: "Traffic", value: "Around 100,000 visitors a month", note: "The eligibility article describes this as approximate.", sourceUrl: "https://help.pubpower.io/article/website-requirements" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Follow PubPower’s content policy; no pop-ups or redirects", note: "Policy bars or restricts sexual, explicit, violent, illegal, gambling, and infringing content.", sourceUrl: "https://help.pubpower.io/article/website-requirements" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Add PubPower ads.txt lines and install its ad tag", sourceUrl: "https://help.pubpower.io/article/quick-start-to-your-monetization" }, { label: "Approval time", value: "Usually 24–48 hours to 2–4 days", note: "Quick-start says 24–48 hours; FAQ says 2–4 days and warns weekends can take longer.", sourceUrl: "https://help.pubpower.io/article/quick-start-to-your-monetization" }], minTraffic: { amount: 100000, unit: "visitors", label: "Around 100,000 visitors a month" }, revenueShare: "Essential publisher revenue share is tailored; Advanced custom bidders have no revenue share", paymentTerms: "Net 0 above $3,000 monthly revenue; otherwise Net 30", paymentThreshold: "Bank: $1,000; PayPal: $100; Payoneer: $50; crypto: BCH $100, BTC $1,000, USDT-ERC20 $1,000", paymentMethods: ["Bank transfer", "PayPal", "Payoneer", "Cryptocurrency (BCH, BTC, USDT-ERC20)"], sources: [{ label: "PubPower publisher packages and revenue-sharing model", url: "https://pubpower.io/" }, { label: "Website requirements", url: "https://help.pubpower.io/article/website-requirements" }, { label: "Content policies", url: "https://help.pubpower.io/article/content-policies" }, { label: "Quick-start and domain review", url: "https://help.pubpower.io/article/quick-start-to-your-monetization" }, { label: "Publisher FAQ and review timing", url: "https://help.pubpower.io/article/getting-started-faqs" }, { label: "Payment methods and terms", url: "https://help.pubpower.io/article/payment-methods-terms" }] },
+ raptive: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "25,000", note: "monthly pageviews", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }, { label: "Your share", value: "75%", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360035078152-Getting-Started-with-Raptive" }, { label: "Pay day", value: "Net 45", sourceUrl: "https://help.raptive.com/hc/en-us/articles/202052255-When-do-I-get-paid" }], joining: [{ label: "Traffic", value: "At least 25,000 pageviews", note: "Monthly", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }, { label: "Visitor location", value: "50% from five countries at 25k–99,999 pageviews; 40% at 100k+", note: "US, UK, Canada, New Zealand, or Australia", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }, { label: "Content", value: "High-quality, original, human-led content", note: "Long-form content on most pages at 25k–99,999 pageviews", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Google Analytics access", note: "Read-only authorization", sourceUrl: "https://help.raptive.com/hc/en-us/articles/6681661647515-Applying-to-Raptive-with-Google-Analytics" }, { label: "Approval time", value: "Not public", sourceUrl: null }, { label: "Domain age", value: "At least six months", sourceUrl: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }], minTraffic: { amount: 25000, unit: "pageviews" }, revenueShare: "75%", paymentTerms: "Net 45; paid on the 15th", paymentThreshold: "$25 for most methods; $100 for wire transfer", paymentMethods: ["US direct deposit", "eCheck or local bank transfer", "PayPal", "Paper check", "Wire transfer"], sources: [{ label: "Creator eligibility", url: "https://help.raptive.com/hc/en-us/articles/360032840891-Who-is-eligible-for-Raptive" }, { label: "Applying with Google Analytics", url: "https://help.raptive.com/hc/en-us/articles/6681661647515-Applying-to-Raptive-with-Google-Analytics" }, { label: "Getting started and share", url: "https://help.raptive.com/hc/en-us/articles/360035078152-Getting-Started-with-Raptive" }, { label: "Payment timing", url: "https://help.raptive.com/hc/en-us/articles/202052255-When-do-I-get-paid" }, { label: "Payment methods", url: "https://help.raptive.com/hc/en-us/articles/360013465192-Payment-Methods" }, { label: "Payment thresholds", url: "https://help.raptive.com/hc/en-us/articles/360025379831-Why-didn-t-I-get-my-Raptive-payment" }] },
+ refinery89: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Payment minimum", value: "€250 or $250", note: "a month, by region", sourceUrl: "https://refinery89.com/docs/faqs/finance/is-there-a-minimum-threshold-for-getting-paid/" }], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Worldwide", sourceUrl: "https://refinery89.com/docs/faqs/about-refinery89/where-does-refinery89-operate-and-offer-its-services/" }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Single Tag for websites or SDK for apps", sourceUrl: "https://refinery89.com/docs/faqs/onboarding/how-can-i-start-working-with-refinery89/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Ask your Publisher Success Manager; no standard schedule is published", paymentThreshold: "€250 or $250, based on region", paymentMethods: ["Bank transfer", "eCheck", "Wire transfer", "PayPal"], sources: [{ label: "Eligibility", url: "https://refinery89.com/docs/faqs/requirements/am-i-eligible/" }, { label: "Publisher service locations", url: "https://refinery89.com/docs/faqs/about-refinery89/where-does-refinery89-operate-and-offer-its-services/" }, { label: "How to start and connect", url: "https://refinery89.com/docs/faqs/onboarding/how-can-i-start-working-with-refinery89/" }, { label: "Payment threshold", url: "https://refinery89.com/docs/faqs/finance/is-there-a-minimum-threshold-for-getting-paid/" }, { label: "Payment timing", url: "https://refinery89.com/docs/faqs/finance/when-do-publishers-get-paid/" }, { label: "Payment methods", url: "https://refinery89.com/docs/faqs/finance/what-are-the-payment-methods-available/" }] },
+ revcontent: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Agreement payment floor", value: "$250", note: "payment-method minimums may differ", sourceUrl: "https://help.revcontent.com/knowledge/publisher-terms" }], joining: [{ label: "Traffic", value: "No traffic minimum", sourceUrl: "https://help.revcontent.com/knowledge/creating-a-revcontent-publisher-account", note: "Applications are reviewed case by case" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No illegal, infringing, pornographic, obscene, illicit-drug, or unlawful-gambling content", sourceUrl: "https://help.revcontent.com/knowledge/publisher-terms" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "After domain approval, Revcontent sends placement choices and widget code", sourceUrl: "https://help.revcontent.com/knowledge/creating-a-revcontent-publisher-account" }, { label: "Approval time", value: "Each application and domain is reviewed by a human team; no timing is stated", sourceUrl: "https://help.revcontent.com/knowledge/creating-a-revcontent-publisher-account" }], minTraffic: { amount: 0, unit: "pageviews" }, revenueShare: "Set in the applicable account or order terms; no standard public rate", paymentTerms: null, paymentThreshold: "$250 in the agreement; method minimums are $100 for US ACH, $100 for international PayPal, and $1,000 for international wire", paymentMethods: ["ACH (US)", "PayPal (international)", "Wire transfer (international)"], sources: [{ label: "Publisher account creation and approval", url: "https://help.revcontent.com/knowledge/creating-a-revcontent-publisher-account" }, { label: "Publisher terms", url: "https://help.revcontent.com/knowledge/publisher-terms" }, { label: "Publisher payment requirements and methods", url: "https://help.revcontent.com/knowledge/publisher-payment-requirements-methods" }] },
+ setupad: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "About 100,000", note: "monthly visitors or sessions; its 2025 guide uses both", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Payment minimum", value: "$100", note: "in published guidance", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Self-serve fee", value: "€0.05", note: "per thousand impressions, for direct self-serve", sourceUrl: "https://setupad.com/setupad-self-serve/" }], joining: [{ label: "Traffic", value: "About 100,000 monthly visitors or sessions", note: "The 2025 guide says 100K+ visitors in its requirements section and 100,000 monthly sessions in its comparison. Current Self-Serve has separate 10M+ monthly-visit plans.", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Visitor location", value: "Main traffic from the US, UK, Canada, or Australia", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Content", value: "Follow Setupad’s quality policy; low-quality sites are not accepted", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Add ads.txt and use Setupad demand sources, including Google", sourceUrl: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "Optional Setupad reseller demand takes 20%; Self-Serve direct demand uses a €0.05 CPM fee", paymentTerms: "Net 60 for published managed terms and optional reseller demand; direct SSP partners pay under their own agreements", paymentThreshold: "$100 in published managed guidance; reseller-demand threshold not stated", paymentMethods: ["Bank transfer", "PayPal", "Payoneer", "Wise", "Revolut", "Paysera"], sources: [{ label: "Setupad publisher requirements and payment guidance", url: "https://setupad.com/blog/best-ad-networks-for-publishers/" }, { label: "Setupad Self-Serve plans, requirements and billing", url: "https://setupad.com/setupad-self-serve/" }, { label: "Setupad current platform overview", url: "https://setupad.com/" }, { label: "Setupad SSP guide", url: "https://setupad.com/blog/top-ssps-for-publishers/" }] },
+ "she-media": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "50,000+", note: "monthly pageviews; smaller sites may be considered case by case", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Your share", value: "75%", note: "gross open-marketplace programmatic revenue; guide updated March 2023", sourceUrl: "https://www.shemedia.com/member-spotlight/member-guide-for-partners" }, { label: "Pay day", value: "Net 35", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }], joining: [{ label: "Traffic", value: "Typically 50,000+ pageviews", note: "Monthly; smaller sites may be considered case by case", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Visitor location", value: "At least 30% US traffic", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Content", value: "Original, high-quality, brand-safe, human-led content", note: "AI-generated images need a clear disclaimer", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Google standing", value: "Good track record with Google ad products and platforms", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Must connect", value: "Google MCM and ads.txt", note: "MCM and ads.txt are part of the onboarding requirements", sourceUrl: "https://support.shemedia.com/hc/en-us/articles/19361668032027-Onboarding-Guide-for-Wordpress-Sites" }, { label: "Approval time", value: "3–4 weeks for a response", note: "Response timing, not a final decision guarantee", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Analytics", value: "Google Analytics access", sourceUrl: "https://apply.shemedia.com/" }, { label: "Site age", value: "At least 90 days", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }, { label: "Ad inventory", value: "Exclusive mobile and desktop banner ads", note: "Affiliate links and banners are exceptions", sourceUrl: "https://www.shemedia.com/partner-network/faqs" }], minTraffic: { amount: 50000, unit: "pageviews", label: "Typically 50,000+ pageviews a month" }, revenueShare: "75% of gross open-marketplace programmatic revenue; up to 75% of direct and private marketplace revenue (Member Guide updated 2023)", paymentTerms: "Net 35 after the month closes", paymentThreshold: "$20 (Member Guide updated 2023)", paymentMethods: ["US direct deposit/ACH", "US check if ACH is unavailable", "PayPal for international publishers", "Wise/ACH or wire for international publishers if approved"], sources: [{ label: "Partner FAQ", url: "https://www.shemedia.com/partner-network/faqs" }, { label: "Publisher application", url: "https://apply.shemedia.com/" }, { label: "WordPress onboarding guide", url: "https://support.shemedia.com/hc/en-us/articles/19361668032027-Onboarding-Guide-for-Wordpress-Sites" }, { label: "Blogger onboarding guide", url: "https://support.shemedia.com/hc/en-us/articles/30950543170971-Onboarding-Guide-for-Blogger-Sites" }, { label: "Member Guide, updated March 2023", url: "https://www.shemedia.com/member-spotlight/member-guide-for-partners" }, { label: "International payment options, updated April 2025", url: "https://support.shemedia.com/hc/en-us/articles/35987097977627-Payment-Options-for-Publishers-Outside-the-US" }] },
+ "snack-media": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Referral program traffic", value: "1 million", note: "impressions; not a general minimum, only for referral eligibility", sourceUrl: "https://www.snack-media.com/referral/" }, { label: "Notice to leave", value: "30 days", sourceUrl: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }], joining: [{ label: "Traffic", value: "Referral program lists 1 million impressions", note: "This is referral-program eligibility; the publisher agreement does not state a universal traffic floor", sourceUrl: "https://www.snack-media.com/referral/" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No hateful, pornographic, illegal, or infringing content", note: "The referral program also excludes sensitive and gambling sites", sourceUrl: "https://www.snack-media.com/brand-safety-policy/" }, { label: "Google standing", value: "Must comply with Google policies for the referral program", sourceUrl: "https://www.snack-media.com/referral/" }, { label: "Must connect", value: "Share live traffic stats and install network tags", note: "Tags must be live within 14 days of the agreement date", sourceUrl: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: "Within 30 days after the month when Snack Media receives the advertiser funds", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher referral eligibility", url: "https://www.snack-media.com/referral/" }, { label: "Brand safety policy", url: "https://www.snack-media.com/brand-safety-policy/" }, { label: "2025 publisher agreement terms", url: "https://cdn.snack-media.com/wp-content/uploads/2025/08/Snack-Ad-Network-Agreement-TCs.pdf" }, { label: "Terms page", url: "https://www.snack-media.com/Ad_Network_Terms_and_Conditions_for_Publishers/" }] },
+ sovrn: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Traffic to join", value: "More than 100,000", note: "monthly visits", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Pay day", value: "Net 45", note: "for most direct publishers; terms may vary", sourceUrl: "https://authcore.atlassian.net/wiki/spaces/KB/pages/2693627510846" }, { label: "Payment minimum", value: "$25", note: "$50 for wire", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-the-minimum-payment-threshold-for-sovrn" }], joining: [{ label: "Traffic", value: "More than 100,000 visits a month", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Current, brand-safe content; no child-directed, unsafe, or copyrighted material", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-sovrn-s-approval-process-for-the-ad-exchange" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Provide an operational business domain and current ads.txt ownership details; intermediaries also need sellers.json", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Approval time", value: "Depends on external checks and possible manual review; no fixed estimate. File updates often show within about two business days.", sourceUrl: "https://knowledge.sovrn.com/kb/what-is-sovrn-s-approval-process-for-the-ad-exchange" }], minTraffic: { amount: 100000, unit: "sessions", label: "More than 100,000 visits a month" }, revenueShare: null, paymentTerms: "Net 45 for most Ad Exchange publishers; individual publisher terms may vary", paymentThreshold: "$25 standard; $50 for wire transfer", paymentMethods: ["PayPal", "ACH (US)", "Wire transfer", "eCheck/local transfer", "Paper check (US)"], sources: [{ label: "Property approval requirements", url: "https://knowledge.sovrn.com/kb/what-is-required-for-sovrn-to-approve-my-property" }, { label: "Approval process and timing", url: "https://knowledge.sovrn.com/kb/what-is-sovrn-s-approval-process-for-the-ad-exchange" }, { label: "Current payment methods", url: "https://knowledge.sovrn.com/kb/how-do-i-get-paid-for-the-ad-exchange" }, { label: "Payment thresholds", url: "https://knowledge.sovrn.com/kb/what-is-the-minimum-payment-threshold-for-sovrn" }, { label: "Payment timing guide", url: "https://authcore.atlassian.net/wiki/spaces/KB/pages/2693627510846" }] },
+ sparteo: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Company and publisher services", url: "https://corporate.sparteo.com/" }, { label: "Publisher technology privacy notice", url: "https://corporate.sparteo.com/services-privacy-notice" }, { label: "Publisher platform case study", url: "https://corporate.sparteo.com/post/w3schools-rpm-uplift-unified-monetisation-stack" }, { label: "Company expansion update", url: "https://corporate.sparteo.com/post/sparteo-strengthens-supply-leadership-to-accelerate-global-expansion" }, { label: "Sparteo company LinkedIn", url: "https://www.linkedin.com/company/sparteo" }] },
+ taboola: { checkedAt: "2026-10-21", keyNumbers: [{ label: "Pay day", value: "Within 45 days", note: "after the month ends", sourceUrl: "https://www.taboola.com/policies/publisher-revshare-terms-and-conditions-1-3-US" }], joining: [{ label: "Traffic", value: "No numeric minimum stated", sourceUrl: "https://pubhelp.taboola.com/hc/en-us/articles/39280014062487-How-To-Get-New-Account" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Own or properly license content and follow the Publisher Policy", sourceUrl: "https://pubhelp.taboola.com/hc/en-us/articles/39280014062487-How-To-Get-New-Account" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install Taboola widget code", sourceUrl: "https://developers.taboola.com/web-integrations/docs/welcome" }, { label: "Approval time", value: "Team responds within 48 hours", note: "This is response timing, not final approval", sourceUrl: "https://pubhelp.taboola.com/hc/en-us/articles/39280014062487-How-To-Get-New-Account" }, { label: "Applicant age", value: "At least 18 years old", sourceUrl: "https://pubhelp.taboola.com/hc/en-us/articles/39280014062487-How-To-Get-New-Account" }], minTraffic: null, revenueShare: "Set in the applicable publisher Order; no standard public percentage", paymentTerms: "Within 45 days after month-end; paid in US dollars", paymentThreshold: null, paymentMethods: ["Payoneer (most publishers); exceptions vary by location"], sources: [{ label: "New publisher account guide", url: "https://pubhelp.taboola.com/hc/en-us/articles/39280014062487-How-To-Get-New-Account" }, { label: "Publisher policy", url: "https://pubhelp.taboola.com/hc/en-us/articles/360033751274-Taboola-Publisher-Policy" }, { label: "Web integration guide", url: "https://developers.taboola.com/web-integrations/docs/welcome" }, { label: "Publisher revenue-share terms", url: "https://www.taboola.com/policies/publisher-revshare-terms-and-conditions-1-3-US" }, { label: "Account setup and payment methods", url: "https://pubhelp.taboola.com/hc/en-us/articles/360003157054-Account-Set-Up" }] },
+ teads: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Not public", sourceUrl: null }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: "Terms vary by contract; revenue-share rates may vary with pageview volume or total revenue", paymentTerms: "Negotiated in the media-partner contract; no standard payment interval is published", paymentThreshold: null, paymentMethods: [], sources: [{ label: "Media owner partnership", url: "https://www.teads.com/media-owners" }, { label: "2025 annual filing describing publisher agreements and negotiated payment timing", url: "https://www.sec.gov/Archives/edgar/data/1454938/000145493826000015/tead-20251231.htm" }] },
+ "the-moneytizer": { checkedAt: "2026-10-21", keyNumbers: [{ label: "Your share", value: "At least 70%", note: "of pre-tax advertiser billings, in its published terms", sourceUrl: "https://www.themoneytizer.com/cgu" }, { label: "Invoice minimum", value: "€50", sourceUrl: "https://www.themoneytizer.com/cgu" }, { label: "Pay day", value: "60 days", note: "after the invoice", sourceUrl: "https://us.themoneytizer.com/category/payments-invoices" }], joining: [{ label: "Traffic", value: "Site statistics are requested and each site is reviewed for advertiser fit; no numeric minimum stated", sourceUrl: "https://www.themoneytizer.com/cgu" }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "No racist, xenophobic, pedophilic, indecent, or illegal content", sourceUrl: "https://www.themoneytizer.com/cgu" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Install ads.txt and ad tags; use a consent banner for EU traffic", sourceUrl: "https://us.themoneytizer.com/publisherguide" }, { label: "Approval time", value: "A quality review follows website registration; no timing stated", sourceUrl: "https://us.themoneytizer.com/publisherguide" }], minTraffic: null, revenueShare: "At least 70% of the pre-tax amount billed to advertisers under published Terms", paymentTerms: "An invoice is generated automatically at the threshold and is payable 60 days after its issue date", paymentThreshold: "€50 under the published Terms; $50 in the US publisher FAQ", paymentMethods: ["Bank transfer", "PayPal"], sources: [{ label: "Publisher terms and conditions", url: "https://www.themoneytizer.com/cgu" }, { label: "Publisher guide", url: "https://us.themoneytizer.com/publisherguide" }, { label: "US payments FAQ", url: "https://us.themoneytizer.com/category/payments-invoices" }] },
+ venatus: { checkedAt: "2026-10-21", keyNumbers: [], joining: [{ label: "Traffic", value: "Not public", sourceUrl: null }, { label: "Visitor location", value: "Not public", sourceUrl: null }, { label: "Content", value: "Pass a human audit and follow Publisher Terms; no hate speech, adult content, illegal sharing or hacking, or promotion of drugs, tobacco, or firearms", sourceUrl: "https://www.venatus.com/brand-safety" }, { label: "Google standing", value: "Not public", sourceUrl: null }, { label: "Must connect", value: "Not public", sourceUrl: null }, { label: "Approval time", value: "Not public", sourceUrl: null }], minTraffic: null, revenueShare: null, paymentTerms: null, paymentThreshold: null, paymentMethods: [], sources: [{ label: "Publisher brand-safety standards", url: "https://www.venatus.com/brand-safety" }, { label: "Publisher contact page", url: "https://www.venatus.com/contact/for-publishers" }, { label: "Venatus company site", url: "https://www.venatus.com/" }, { label: "Venatus company LinkedIn", url: "https://www.linkedin.com/company/we-are-venatus" }] },
};
diff --git a/app/(site)/(directories)/ad-networks/niches/[niche]/niche-view.tsx b/app/(site)/(directories)/ad-networks/niches/[niche]/niche-view.tsx
index 67fb8529..ea7f295c 100644
--- a/app/(site)/(directories)/ad-networks/niches/[niche]/niche-view.tsx
+++ b/app/(site)/(directories)/ad-networks/niches/[niche]/niche-view.tsx
@@ -106,6 +106,7 @@ export function NicheView({ breadcrumbs, data, Intro, title, updatedAt }: {
noun={noun}
route={`/ad-networks/niches/${niche.slug}`}
scope={{ niche: niche.slug }}
+ sorts={["traffic", "oldest", "newest", "domain"]}
/>
{niche.networks.length ? (
diff --git a/app/(site)/(directories)/ad-networks/niches/content/article.mdx b/app/(site)/(directories)/ad-networks/niches/content/article.mdx
index 0d5b8d6d..ffbc4332 100644
--- a/app/(site)/(directories)/ad-networks/niches/content/article.mdx
+++ b/app/(site)/(directories)/ad-networks/niches/content/article.mdx
@@ -1,7 +1,30 @@
-## How do we sort sites into niches?
+## How do you pick an ad network for your niche?
-Niches are estimates based on each site's homepage text. A site that covers several topics goes into its main one. Low confidence guesses stay unsorted and don't count toward any niche here.
+Find your niche in the table and see which networks sites like yours already run. Then narrow it down:
+
+1. Look past Google AdSense. It takes sites of any size, so it leads almost every niche. The second and third networks show which managed networks your niche favors.
+2. See which is easiest to join. The table names the easiest of the top three, with its traffic minimum.
+3. Open your niche's page, such as [food](/ad-networks/niches/food) or [travel](/ad-networks/niches/travel), to see every network its sites use and how big those sites are.
+4. Open a network's page and filter its sites by your niche. If sites your size run it, it's a realistic next step.
+
+
+Pick the closest one. A recipe site with a lot of gardening posts will learn most from both food and gardening.
+
+
+## What does the table tell you?
+
+Each row is one niche. `Sites` counts the sites we've sorted into it, and `share of all sites` is how big that niche is next to the others.
+
+`Top networks` shows the share of the niche's sites that run each network. The grid below it shows the same shares for more networks at once, with darker cells for bigger shares.
+
+`Easiest of these to join` is blank when none of the three publishes a traffic minimum. The network's page lists its other rules.
+
+Each site sits in one niche: its main topic. Sites we couldn't place aren't counted on this page.
## Why can a niche's shares add up to more than 100%?
Many sites run more than one ad network at the same time. Each share counts the sites that use that network, so one site can count toward several networks in the same niche.
+
+## Does a big share mean a network suits your niche?
+
+It's a good sign, not proof. A big share shows the network accepts sites like yours and that they're still running it. But a share counts sites, not earnings, so check each network's requirements and pay on its own page before you apply.
diff --git a/app/(site)/(directories)/ad-networks/niches/niches-view.tsx b/app/(site)/(directories)/ad-networks/niches/niches-view.tsx
index 7d7aae16..26811c4b 100644
--- a/app/(site)/(directories)/ad-networks/niches/niches-view.tsx
+++ b/app/(site)/(directories)/ad-networks/niches/niches-view.tsx
@@ -7,7 +7,6 @@ import { DirectoryTitleIcon } from "@/app/ui/directories/directory-title-icon";
import { NichesTable, type NicheTableRow } from "@/app/ui/ad-networks/niches-table";
import { AdSection } from "@/app/ui/ad-networks/section";
import { Heatmap } from "@/app/ui/ad-networks/viz/heatmap";
-import { Treemap } from "@/app/ui/ad-networks/viz/treemap";
import { AppShell } from "@/app/ui/site/app-shell";
import { EntryHero } from "@/app/ui/site/entry-hero";
import { PageCanvas } from "@/app/ui/site/page-canvas";
@@ -28,7 +27,7 @@ const shortName = (name: string) => name.replace(/^Google /, "").replace(/ by Me
const networkHref = (slug: string) => `/ad-networks/${slug}`;
/**
- * The niches index (mockup `niches.html`): sites per niche, each niche's top networks, and the
+ * The niches index (mockup `niches.html`): each niche's sites and top networks in one table, and the
* niche by network grid. Takes loader data so it can be checked with any data.
*/
export function NichesView({ breadcrumbs, data, nicheHref, title, updatedAt }: {
@@ -73,9 +72,6 @@ export function NichesView({ breadcrumbs, data, nicheHref, title, updatedAt }: {
{/* data-gate: the niche run sorts sites into niches; until it reaches coverage the loader returns none and these sections hide. */}
{niches.length ? (
<>
-
- ({ label: niche.name, value: niche.listed, href: nicheHref(niche.slug) }))} total={data.classified} />
-
/^(typically|around|about)\b/i.test(rule.label ?? "")).map((rule) => shortName(rule.name));
+ const guideNote = guideNames.length
+ ? ` ${guideNames.length === 1 ? guideNames[0] : `${guideNames.slice(0, -1).join(", ")} and ${guideNames.at(-1)}`} give a typical level, not a firm minimum.`
+ : "";
const ageRows = data.median_domain_age.slice(0, 9).map((row) => ({ label: row.name, shortLabel: shortName(row.name), value: Math.round(row.years) }));
const wordpressRows = data.wordpress_share.slice(0, 8)
.map((row) => ({ label: row.name, value: row.share, display: percent(row.share), href: `/ad-networks/${row.slug}` }));
@@ -236,8 +242,8 @@ export default async function AdNetworkStatsPage() {
{scatter.length > 1 ? (
-
-
+
+
) : null}
{ageRows.length ? (
diff --git a/app/(site)/(tools)/ad-network-checker/ad-network-checker-tool.tsx b/app/(site)/(tools)/ad-network-checker/ad-network-checker-tool.tsx
index a6c78236..5b87eb36 100644
--- a/app/(site)/(tools)/ad-network-checker/ad-network-checker-tool.tsx
+++ b/app/(site)/(tools)/ad-network-checker/ad-network-checker-tool.tsx
@@ -116,8 +116,9 @@ export function AdNetworkCheckerTool({ initialSite = "", logos = {} }: { initial
if (initialSite) void check(initialSite, false);
}, [initialSite]); // eslint-disable-line react-hooks/exhaustive-deps
- // Stop a check still running when the tool goes away. A remount starts its own check.
- useEffect(() => () => request.current?.abort(), []);
+ // A check still running when the tool goes away is left to finish: its result is ignored, and
+ // its own `finally` clears loading if the tool comes back (Fast Refresh keeps state). Aborting
+ // here raised an unhandled AbortError in development. A new check or Reset still aborts it.
useEffect(() => {
if (!focusTitle.current || loading) return;
diff --git a/app/(site)/(tools)/ad-network-checker/content/article.mdx b/app/(site)/(tools)/ad-network-checker/content/article.mdx
index 93c3372f..6b7cb445 100644
--- a/app/(site)/(tools)/ad-network-checker/content/article.mdx
+++ b/app/(site)/(tools)/ad-network-checker/content/article.mdx
@@ -1,3 +1,13 @@
+## What can I do with the result?
+
+It depends on why you're checking:
+
+| If you're | Look at |
+| --- | --- |
+| Choosing a network | Check a few sites in your niche that are a little bigger than yours. If they run the same network, open its page in the [ad networks directory](/ad-networks) to see what it takes to join and how it pays. `Similar sites` shows more sites on that network. |
+| Checking your own site | After you join a network, check that its `MANAGERDOMAIN` line or seller lines show here. If a network you left still shows, its lines are probably still in your ads.txt file. |
+| Buying a site | See which networks it runs and how that changed over time. A recent switch is worth asking the seller about. |
+
## How do I find out which ad network a website uses?
Open the site's ads.txt file by adding `/ads.txt` to its address, such as `example.com/ads.txt`. Look for a line that starts with `MANAGERDOMAIN`. If it's there, it names the company that manages the site's ads.
@@ -20,11 +30,28 @@ Each line authorizes one ad account to sell the site's space. `DIRECT` means the
A network such as Mediavine works with dozens of ad exchanges, and each one needs its own line. That's why one network can add dozens of lines. The [IAB's ads.txt page](https://iabtechlab.com/ads-txt/) explains the format in full.
+## How do I set up ads.txt on my own site?
+
+Put a plain text file named `ads.txt` at the root of your domain, so it opens at `yoursite.com/ads.txt`. Your ad network gives you the lines to add. Each line has up to four parts:
+
+```text
+google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0
+```
+
+| Part | What it is |
+| --- | --- |
+| `google.com` | The ad system that sells your space. |
+| `pub-0000000000000000` | Your account ID with that ad system. |
+| `DIRECT` | You hold the account yourself. `RESELLER` means a partner sells on your behalf. |
+| `f08c47fec0942fa0` | Optional. The ad system's ID with the Trustworthy Accountability Group. |
+
+Ad buyers use this file to check who may sell your space, and they can skip sellers it doesn't list. When you switch networks, replace the old network's lines with the new ones.
+
## Why isn't a site in the results?
We only show sites our checker has read. We find sites from public lists and each network's own seller list, then read their ads.txt on a schedule. A new or small site may not be in our list yet.
-A site also stays out when we can't confirm a network we track. That includes sites with no ads.txt file, sites that block our checker, and sites that use a network outside our list. The [ad networks directory](/ad-networks) lists every network we track.
+A site also stays out when we can't confirm a network we track. That includes most sites with no ads.txt file (a few networks can be confirmed from homepage ad code alone), sites that block our checker, and sites that use a network outside our list. The [ad networks directory](/ad-networks) lists every network we track.
## How current is the result?
@@ -34,8 +61,8 @@ The `Since` month is when we first confirmed a network. If that was our first ch
One missed check never removes a network. A timeout or a blocked request counts as unknown. A network moves to `Not seen lately`, then `Ended`, only after repeated checks find it missing.
-## Does stack127 show traffic or earnings?
+## What does the traffic group mean?
-Not yet. Traffic and niche join the site facts as our data runs finish. We don't estimate earnings, because there's no public source we can check them against.
+It's the site's place in Google's list of the million most visited sites by Chrome users: `top 10k`, `top 100k`, or `top 1M`. `Not ranked` means the site wasn't in this month's list. That doesn't mean zero traffic: the list only covers sites with enough Chrome visitors.
-If you're choosing a network for your own site, the [ad networks directory](/ad-networks) shows each network's sites and how to join.
+We don't show visit counts or estimate earnings, because there's no public source we can check them against.
diff --git a/app/api/ad-networks/input.ts b/app/api/ad-networks/input.ts
index a51b09a5..fd1b8a94 100644
--- a/app/api/ad-networks/input.ts
+++ b/app/api/ad-networks/input.ts
@@ -17,7 +17,7 @@ export function parseAdNetworkSitesParams(params: URLSearchParams): AdNetworkSit
const network = params.get("network") || null;
const niche = params.get("niche") || null;
const q = (params.get("q") ?? "").trim().toLowerCase();
- const sort = params.get("sort") ?? "domain";
+ const sort = params.get("sort") ?? (network || niche ? "traffic" : "domain");
if (network && (network.length > 100 || !slug.test(network))) throw new AdNetworkInputError("Invalid network.");
if (niche && !getAdNetworkNiche(niche)) throw new AdNetworkInputError("Invalid niche.");
if (q.length > 100 || /[\x00-\x1f\x7f]/.test(q)) throw new AdNetworkInputError("Search must be at most 100 characters.");
diff --git a/app/ui/ad-networks/details.tsx b/app/ui/ad-networks/details.tsx
index 8fa89826..c704962e 100644
--- a/app/ui/ad-networks/details.tsx
+++ b/app/ui/ad-networks/details.tsx
@@ -44,8 +44,8 @@ export function FactsList({ items }: { items: readonly Fact[] }) {
}
/** For a fact the network doesn't publish. Research says so; it isn't missing data. */
-export function NotPublic() {
- return Not public;
+export function NotPublic({ label = "Not public" }: { label?: string }) {
+ return {label};
}
/**
diff --git a/content_docs/ad-networks/brief.md b/content_docs/ad-networks/brief.md
index 2000290d..4ac56cee 100644
--- a/content_docs/ad-networks/brief.md
+++ b/content_docs/ad-networks/brief.md
@@ -11,3 +11,25 @@ The source of truth is the three table model in [plan.md](plan.md): network iden
The parent and 45 child registry rows remain unpublished in development and production. Shipping their code, identity data, and docs does not launch the directory. The managed publisher and relationship tables remain empty; the independent homelab SQLite queue is preserved.
The two GitHub discovery and verification workflows are manual previews. They have no schedules and run without `--apply`, so they do not save candidates or verification results. Enabling production writes, copying reviewed SQLite results, scheduling production refreshes, and publishing pages each need a separate activation review.
+
+## Search words
+
+Checked 2026-10-20. See "Find the words first" in `stack127_docs/writing-style.md`.
+
+| Page | Main phrase | Words top titles add | The gap |
+| --- | --- | --- | --- |
+| Network pages | " requirements", " payout", " minimum traffic" | the year, "how to qualify", the minimum itself, "review", "alternatives" | Many top results still quote old minimums, such as 100,000 pageviews for Raptive, 50,000 sessions for Mediavine, or 10,000 for Ezoic. Few link the network's own page, and none show which sites run it. |
+| Niche pages | "best ad networks for blogs", " websites" | best, a count (top 10), the year | Lists are opinion, often written by a network that ranks itself first, and many are from 2024. None show which networks real sites in the niche run. |
+| Niches index | "ad networks by niche", "best ad networks for " | best, the niche names | No result compares niches side by side. |
+| Directory home | "ad networks for publishers", "best ad networks for publishers" | best, the year, a count, "requirements", "high paying" | Vendor blogs list themselves. Requirement tables go stale and give no sources. |
+| Stats | "ad network market share" | statistics, the year | W3Techs shows Google at 99% of sites, which says nothing about managed networks such as Mediavine or Raptive. |
+| Checker | "which ad network does a site use", "ad network checker", "detector" | find, free, extension | Most tools are small browser extensions. Few say how they decide, or tell a listing in ads.txt from the network that runs the site. |
+
+Questions people ask: how many pageviews does Raptive or Mediavine need, does Ezoic still take small sites, which ad network pays the most, what is the AdSense payout minimum, and which ad network does a given site use.
+
+### Titles
+
+- Network pages: " requirements (2026): ". The rule is the joining minimum when the network publishes one, then its share or payout terms. Networks that publish neither lead with the sites we list. The H1 says "What it takes to join , what it pays, and N+ sites using it". Facts come from `network-facts.ts` and `research/.md`. The year goes in because these rules change.
+- Niche pages: "Ad networks for blogs or sites: what N+ real ones run". The H1 asks "Which ad networks do sites use? We checked N+". The description names the networks after AdSense with the most sites in that niche.
+- Counts are rounded down from the smaller of the development and production counts, with room for normal drift. Update a title when its count passes the next round number, or a network changes the rule the title names. Titles skip counts under 100, and pages with no listed sites don't mention sites.
+- No title says "best". The records show which networks sites run, not which one is best for a reader.
diff --git a/lib/ad-networks-report.ts b/lib/ad-networks-report.ts
index 56dc53d6..3b6f7e86 100644
--- a/lib/ad-networks-report.ts
+++ b/lib/ad-networks-report.ts
@@ -30,7 +30,9 @@ export function adNetworkSiteAvailability(coverage: AdNetworkSiteCoverage): AdNe
const availableColumns: AdNetworkSitesAvailability["availableColumns"] = ["domain"];
const availableSorts: AdNetworkSitesAvailability["availableSorts"] = ["domain"];
const availableFilters: AdNetworkSitesAvailability["availableFilters"] = [];
- const nicheReady = hasAdNetworkNicheCoverage(coverage.listed, coverage.classified);
+ // The table shows niches as soon as any site in scope has one; unsorted rows read "Not listed".
+ // Niche charts and pages keep the stricter hasAdNetworkNicheCoverage gate.
+ const nicheReady = coverage.classified > 0;
// data-gate: niche run; traffic run; RDAP run; platform run; publisher-name run; verifier.
if (nicheReady) { availableColumns.push("niche"); availableFilters.push("niche"); }
if (coverage.traffic > 0) { availableColumns.push("traffic"); availableSorts.push("traffic"); }
diff --git a/lib/ad-networks-types.ts b/lib/ad-networks-types.ts
index 786e40f7..9eb1d75f 100644
--- a/lib/ad-networks-types.ts
+++ b/lib/ad-networks-types.ts
@@ -161,7 +161,7 @@ export type AdNetworkCheckerSiteView = {
};
export type AdNetworkSiteResponse = { domain: string; found: boolean; site: AdNetworkCheckerSiteView | null };
-export type AdNetworkJoiningRule = AdNetworkRef & { amount: number; unit: "sessions" | "pageviews" | "visitors" };
+export type AdNetworkJoiningRule = AdNetworkRef & { amount: number; unit: "sessions" | "pageviews" | "visitors"; label?: string };
export type AdNetworkDirectorySort = "most-sites" | "easiest-to-join" | "by-niche";
export type AdNetworkDirectoryCard = AdNetworkListRow & {
confirmed_share: number | null; rank: number | null; minTraffic: AdNetworkJoiningRule | null;
diff --git a/lib/ad-networks.ts b/lib/ad-networks.ts
index ce6fe644..7b6562cb 100644
--- a/lib/ad-networks.ts
+++ b/lib/ad-networks.ts
@@ -18,19 +18,28 @@ import type { AdNetworkSiteCoverage } from "./ad-networks-report";
import { adNetworkFacts } from "../app/(site)/(directories)/ad-networks/network-facts";
import { getPool } from "./db";
-import type { QueryResultRow } from "pg";
+import type { QueryResult, QueryResultRow } from "pg";
import { unstable_cache } from "next/cache";
import { AD_NETWORKS_TAG } from "./cache-tags";
let reportQueries = 0;
const waitingReports: (() => void)[] = [];
-/** Leave one of the shared pool's four connections for page registry queries. */
-export async function queryAdNetworkReport(sql: string, values?: unknown[]) {
+// The managed development database stalls when cold reports compete for its CPU.
+// Production keeps three readers, leaving one pool connection for page registry queries.
+const reportQueryLimit = process.env.NODE_ENV === "development" ? 1 : 3;
+export async function queryAdNetworkReport(sql: string, values?: unknown[]): Promise> {
await new Promise(resolve => {
- if (reportQueries < 3) { reportQueries++; resolve(); }
+ if (reportQueries < reportQueryLimit) { reportQueries++; resolve(); }
else waitingReports.push(resolve);
});
- try { return await getPool().query(sql, values); }
+ try {
+ // Cold scans on the managed dev instance can exceed the shared pool's 15s
+ // budget even when reading cached database pages. Keep production unchanged.
+ const developmentQuery = { text: sql, values, query_timeout: 60000 };
+ return await (process.env.NODE_ENV === "development"
+ ? getPool().query(developmentQuery)
+ : getPool().query(sql, values));
+ }
finally {
const next = waitingReports.shift();
if (next) next();
@@ -154,11 +163,23 @@ export async function listVerifiedPublishers(networkId: string, query: string, p
/** Every cached response is an aggregate or a bounded page. Never cache an entire site catalog. */
function cached(key: string, loader: (...args: T) => Promise) {
+ // Concurrent pages can miss the same Next cache entry during a cold refresh.
+ // Share the pending read, then let Next own the stored result and invalidation.
+ const pending = new Map>();
return unstable_cache(async (...args: T) => {
- const result = await loader(...args);
- if (Buffer.byteLength(JSON.stringify(result)) >= 1_900_000) throw new Error(`${key} exceeds cache entry budget`);
- return result;
- }, [key, "v13"], { revalidate: false, tags: [AD_NETWORKS_TAG] });
+ const argumentKey = JSON.stringify(args);
+ let read = pending.get(argumentKey);
+ if (!read) {
+ read = (async () => {
+ const result = await loader(...args);
+ if (Buffer.byteLength(JSON.stringify(result)) >= 1_900_000) throw new Error(`${key} exceeds cache entry budget`);
+ return result;
+ })();
+ pending.set(argumentKey, read);
+ }
+ try { return await read; }
+ finally { if (pending.get(argumentKey) === read) pending.delete(argumentKey); }
+ }, [key, "v15"], { revalidate: false, tags: [AD_NETWORKS_TAG] });
}
const iso = (value: Date | string | null): string | null => value === null ? null : new Date(value).toISOString();
const ref = (network: AdNetworkRef): AdNetworkRef => ({ slug: network.slug, name: network.name });
@@ -189,7 +210,7 @@ const siteProjection = `p.normalized_domain as domain, p.publisher_name, p.niche
// Reports need the same evidence as individual rows, but must aggregate the
// relationship table once instead of running JSON subqueries per publisher.
-const reportMemberships = `with relationship_facts as materialized (
+const reportMemberships = `with relationship_facts as (
select r.publisher_id,n.slug,r.status,r.relationship_type,
case when r.status='confirmed' and r.relationship_type='primary_or_exclusive_manager'
then jsonb_build_object('manager_domain',r.report_retained_manager) end as manager_evidence
@@ -205,7 +226,7 @@ const reportManagerEvidence = `jsonb_build_object('manager_domains',p.last_check
export async function loadAdNetworkManagerStatistics() {
const [groups,identities]=await Promise.all([
queryAdNetworkReport<{evidence:unknown;manager_relationships:SiteRecord["manager_relationships"];network_slugs:string[];has_summary:boolean;count:number}>(`
- with memberships as materialized (${reportMemberships}), publishers as materialized (
+ with memberships as (${reportMemberships}), publishers as (
select p.id,jsonb_build_object('manager_domains',p.report_manager_domains) as last_check_evidence,
p.report_has_ads_txt_summary as has_summary from public.ad_network_publishers p
), records as (
@@ -264,7 +285,7 @@ const scopedManagerSites = `with sites as materialized (select p.id,
and ($2::text is null or p.niche=$2))`;
export const getAdNetworkSitesAvailability=cached("ad-network-sites-availability",loadAdNetworkSitesAvailability);
const siteSort: Record = {
- domain: "p.normalized_domain", traffic: "case p.traffic_group when 'top-1k' then 0 when 'top-10k' then 1 when 'top-100k' then 2 when 'top-1m' then 3 when 'not-ranked' then 4 else 5 end,p.normalized_domain",
+ domain: "p.normalized_domain", traffic: "case p.traffic_group when 'top-1k' then 0 when 'top-10k' then 1 when 'top-100k' then 2 when 'top-1m' then 3 when 'not-ranked' then 4 else 5 end,p.domain_created_on asc nulls last,p.normalized_domain,p.id",
oldest: "p.domain_created_on asc nulls last,p.normalized_domain",
newest: "p.domain_created_on desc nulls last,p.normalized_domain",
checked: "p.last_checked_at desc nulls last,p.normalized_domain",
@@ -296,9 +317,9 @@ export async function loadAdNetworkSites(query: AdNetworkSitesQuery): Promise toSite(row, identities)), total, page, pageSize: query.pageSize, totalPages, effectiveSort, ...availability };
}
-export const getAdNetworkSites=cached("ad-network-sites",loadAdNetworkSites);
+export const getAdNetworkSites=cached("ad-network-sites-traffic-age",loadAdNetworkSites);
export function defaultAdNetworkSitesQuery(network: string | null = null, niche: AdNetworkNicheSlug | null = null, pageSize = AD_NETWORK_SITES_PAGE_SIZE): AdNetworkSitesQuery {
- return { network, niche, q: "", sort: "domain", page: 1, pageSize };
+ return { network, niche, q: "", sort: network || niche ? "traffic" : "domain", page: 1, pageSize };
}
const scopedSites = `with sites as materialized (select p.id,p.normalized_domain,p.niche,p.publisher_name,p.traffic_group,p.platform,p.domain_created_on
@@ -394,9 +415,11 @@ async function queryDomainAgeStrips(network: string | null,niche: string | null,
from records group by scope_key,name
), bins as (
select scope_key,year,count(*)::int as count from records group by scope_key,year
- ) select summaries.*,coalesce((select jsonb_agg(jsonb_build_object('year',b.year,'count',b.count) order by b.year)
- from bins b where b.scope_key=summaries.scope_key),'[]'::jsonb) as bins
- from summaries order by scope_key`,[network,niche,byNetwork])).rows;
+ ), histograms as (
+ select scope_key,jsonb_agg(jsonb_build_object('year',year,'count',count) order by year) as bins
+ from bins group by scope_key
+ ) select summaries.*,coalesce(histograms.bins,'[]'::jsonb) as bins
+ from summaries left join histograms using (scope_key) order by scope_key`,[network,niche,byNetwork])).rows;
}
function toDomainAgeStrip(row: DomainAgeRecord | undefined): AdNetworkDomainAgeStrip | null {
@@ -532,7 +555,7 @@ export const getAdNetworkNichesPageData = cached("ad-network-niches-page", async
export async function loadAdNetworkTrafficShares(niche: string | null): Promise {
const [groups,identities] = await Promise.all([
queryAdNetworkReport<{traffic_group:string;evidence:unknown;manager_relationships:SiteRecord["manager_relationships"];count:number}>(`
- with memberships as materialized (${reportMemberships}), publishers as materialized (
+ with memberships as (${reportMemberships}), publishers as (
select p.id,p.traffic_group,jsonb_build_object('manager_domains',p.report_manager_domains) as last_check_evidence
from public.ad_network_publishers p
where p.traffic_group is not null and ($1::text is null or p.niche=$1)
@@ -545,7 +568,8 @@ export async function loadAdNetworkTrafficShares(niche: string | null): Promise<
return aggregateAdNetworkTrafficShares(groups.rows,identities);
}
const loadTrafficShares = cached("ad-network-traffic-shares",loadAdNetworkTrafficShares);
-export const getAdNetworkNichePageData = cached("ad-network-niche-page", async (slug: string): Promise => {
+// This payload includes the default table view; retire cached A–Z initial rows.
+export const getAdNetworkNichePageData = cached("ad-network-niche-page-traffic", async (slug: string): Promise => {
const asOf=new Date().toISOString().slice(0,10);
const definition=getAdNetworkNiche(slug);
if (!definition) return null;
@@ -631,6 +655,27 @@ export async function loadAdNetworkCheckerSite(domain: string): Promise {
+ return (await queryAdNetworkReport(`with first_listed as (
+ select publisher_id,min(observed_at) as first_seen_at from public.ad_network_relationship_events
+ where event='newly_found' group by publisher_id
+ ), checker_sources as materialized (
+ select id from public.ad_network_publishers where discovery_sources @> '[{"source_key":"checker"}]'
+ ), attributed_sources as materialized (
+ select id from public.ad_network_publishers where jsonb_array_length(discovery_sources)>0
+ ) select date_trunc('week',f.first_seen_at at time zone 'UTC')::date::text as week,
+ count(*) filter(where checker.id is null)::int as discovered,
+ count(*) filter(where checker.id is not null)::int as checker
+ from first_listed f left join checker_sources checker on checker.id=f.publisher_id
+ left join attributed_sources attributed on attributed.id=f.publisher_id
+ where f.first_seen_at>=date_trunc('week',now() at time zone 'UTC')-interval '12 weeks'
+ and f.first_seen_at => {
const pool={query:queryAdNetworkReport};
const observedDay=new Date();
@@ -676,16 +721,7 @@ export const getAdNetworkStatsPageData = cached("ad-network-market-report", asyn
select count(*) filter(where last_checked_at>=now()-interval '7 days')::int as checked_last_7_days,
(select count(*)::int from first_listed where first_seen_at>=date_trunc('week',now() at time zone 'UTC')-interval '7 days'
and first_seen_at(`with first_listed as (
- select publisher_id,min(observed_at) as first_seen_at from public.ad_network_relationship_events
- where event='newly_found' group by publisher_id)
- select date_trunc('week',f.first_seen_at at time zone 'UTC')::date::text as week,
- count(*) filter(where not discovery_sources @> '[{"source_key":"checker"}]')::int as discovered,
- count(*) filter(where discovery_sources @> '[{"source_key":"checker"}]')::int as checker
- from first_listed f join public.ad_network_publishers p on p.id=f.publisher_id
- where f.first_seen_at>=date_trunc('week',now() at time zone 'UTC')-interval '12 weeks'
- and f.first_seen_at0) order by 1 limit 12`),
+ loadAdNetworkWeeklyDiscoveries(),
loadMovements(null,asOf),getAdNetworkManagerStatistics(),loadReportMetadata(null),
pool.query<{total:number;checked:number;waiting:number}>(`select count(*)::int as total,
count(*) filter(where last_checked_at is not null)::int as checked,
@@ -723,7 +759,7 @@ export const getAdNetworkStatsPageData = cached("ad-network-market-report", asyn
// data-gate: real new-site observations populate the weekly count; imported baselines are excluded.
new_last_week:movements.some(row=>(row.newly_found??0)>0) ? freshness.rows[0].new_last_week : null,
// data-gate: every site in a week needs source attribution before scan/checker stacks are shown.
- weekly:weekly.rows}};
+ weekly}};
});
function joiningRules(networks: AdNetworkRef[]): AdNetworkJoiningRule[] {
diff --git a/supabase/migrations/20261020174015_ad_network_discovery_source_report_indexes.sql b/supabase/migrations/20261020174015_ad_network_discovery_source_report_indexes.sql
new file mode 100644
index 00000000..2685bd6b
--- /dev/null
+++ b/supabase/migrations/20261020174015_ad_network_discovery_source_report_indexes.sql
@@ -0,0 +1,16 @@
+-- Weekly discovery reports need two source flags, not the publishers' JSON.
+-- Partial ID indexes allow index-only membership checks without copying JSON
+-- into another covering index or adding generated columns to the wide table.
+-- At ~107k publishers, even the all-publisher index is about 2.4 MiB.
+-- Plain builds briefly block publisher writes. Fail fast instead of queueing
+-- behind an ad-network sync; the release can be retried once it finishes.
+set local lock_timeout = '5s';
+set local statement_timeout = '60s';
+
+create index if not exists ad_network_publishers_attributed_source_report_idx
+ on public.ad_network_publishers (id)
+ where jsonb_array_length(discovery_sources)>0;
+
+create index if not exists ad_network_publishers_checker_source_report_idx
+ on public.ad_network_publishers (id)
+ where discovery_sources @> '[{"source_key":"checker"}]'::jsonb;
diff --git a/tests/helpers/load-typescript.mjs b/tests/helpers/load-typescript.mjs
index ca3204c4..45c99fae 100644
--- a/tests/helpers/load-typescript.mjs
+++ b/tests/helpers/load-typescript.mjs
@@ -8,7 +8,7 @@ export function loadTypeScript(file, imports) {
compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.CommonJS },
}).outputText;
vm.runInNewContext(code, {
- exports, URL, URLSearchParams, Response,
+ exports, URL, URLSearchParams, Response, process,
require(name) {
if (Object.hasOwn(imports, name)) return imports[name];
throw new Error(`Unexpected import: ${name}`);
diff --git a/tests/pages/ad-networks/cache-verification.test.mjs b/tests/pages/ad-networks/cache-verification.test.mjs
index 710a549e..34dfba11 100644
--- a/tests/pages/ad-networks/cache-verification.test.mjs
+++ b/tests/pages/ad-networks/cache-verification.test.mjs
@@ -7,6 +7,10 @@ import * as niches from '../../../lib/ad-network-niches.ts';
import {cacheBodyDigest} from '../../../scripts/stack127/cache/refresh.mjs';
import {targetsForEvents} from '../../../scripts/stack127/cache/targets.mjs';
import {refreshApiRecords} from '../../../scripts/stack127/frontend/content-queue.mjs';
+import {parseAdNetworkSitesParams} from '../../../app/api/ad-networks/input.ts';
+import {adNetworksLibrary} from './loader-harness.mjs';
+
+const {defaultAdNetworkSitesQuery}=adNetworksLibrary(()=>{throw Error('Defaults must not query the database');});
function load(file,imports,globals={}) {
const exports={};
@@ -27,7 +31,7 @@ function sourceProbe({published=true}={}) {
}})},
'./ad-network-niches':niches,
'./ad-networks':{
- defaultAdNetworkSitesQuery:network=>({network,niche:null,q:'',page:1,pageSize:10,sort:'domain'}),
+ defaultAdNetworkSitesQuery,
loadAdNetworkSites:async query=>{calls.push(['sites',query]);return {rows:[{domain:query.q}],total:1};},
loadAdNetworkCheckerSite:async domain=>{calls.push(['site',domain]);return {site:{domain,managed_by:{slug:'mediavine'}}};},
getAdNetworkSites:()=>{throw Error('Cached getter used as source');},getAdNetworkCheckerSite:()=>{throw Error('Cached getter used as source');},
@@ -56,6 +60,9 @@ test('representative API checks use direct source loaders and real request param
const sites=await probe.getAdNetworkApiVerification('/api/ad-networks/sites');
assert.equal(new URL(sites.requestPath,'https://stack127.com').searchParams.get('q'),'collegefashion.net');
assert.equal(probe.calls[0][0],'sites');assert.equal(probe.calls[0][1].network,'mediavine');
+ assert.equal(probe.calls[0][1].sort,'traffic');
+ assert.deepEqual(JSON.parse(JSON.stringify(probe.calls[0][1])),
+ parseAdNetworkSitesParams(new URL(sites.requestPath,'https://stack127.com').searchParams));
const site=await probe.getAdNetworkApiVerification('/api/ad-networks/site');
assert.equal(site.requestPath,'/api/ad-networks/site?domain=collegefashion.net');
assert.equal(site.expected.site.site.managed_by.slug,'mediavine');
diff --git a/tests/pages/ad-networks/loader-harness.mjs b/tests/pages/ad-networks/loader-harness.mjs
index fe91d4af..dc1f2927 100644
--- a/tests/pages/ad-networks/loader-harness.mjs
+++ b/tests/pages/ad-networks/loader-harness.mjs
@@ -20,7 +20,7 @@ export function adNetworksLibrary(query, overrides={}, globals={}) {
const code=ts.transpileModule(fs.readFileSync(new URL('../../../lib/ad-networks.ts',import.meta.url),'utf8'),{
compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.CommonJS},
}).outputText;
- vm.runInNewContext(code,{exports,Buffer,URL,URLSearchParams,require(name){
+ vm.runInNewContext(code,{exports,Buffer,URL,URLSearchParams,process,require(name){
if(Object.hasOwn(imports,name))return imports[name];throw Error(`Unexpected import: ${name}`);
},...globals});
return exports;
diff --git a/tests/pages/ad-networks/report-projections-database.test.mjs b/tests/pages/ad-networks/report-projections-database.test.mjs
index 08ac0720..2eccf565 100644
--- a/tests/pages/ad-networks/report-projections-database.test.mjs
+++ b/tests/pages/ad-networks/report-projections-database.test.mjs
@@ -37,3 +37,68 @@ test('compact database projections preserve manager resolution and ambiguity', {
}
} finally {await pool.end();}
});
+
+test('domain-age SQL keeps each network histogram, distinct market sites and exact endpoint ties', {skip:!connectionString}, async()=>{
+ const {adNetworksLibrary}=await import('./loader-harness.mjs');
+ const client=new pg.Client({connectionString,connectionTimeoutMillis:15000,query_timeout:15000,
+ options:'-c default_transaction_read_only=on'});
+ const fixtures=`with fixture_publishers(id,normalized_domain,niche,domain_created_on) as (values
+ (1,'a.example','food','2000-01-01'::date),(2,'b.example','food','2010-06-01'::date),
+ (3,'c.example','tech','2020-12-31'::date),(4,'unknown.example','food',null::date),
+ (5,'ended.example','food','1980-01-01'::date),(6,'z.example','food','2000-01-01'::date)),
+ fixture_networks(id,slug,name) as (values (1,'a','A'),(2,'b','B'),(3,'empty','Empty')),
+ fixture_relationships(publisher_id,ad_network_id,status) as (values
+ (1,1,'confirmed'),(1,2,'stale'),(2,1,'stale'),(3,2,'confirmed'),
+ (4,1,'confirmed'),(5,1,'ended'),(6,1,'confirmed')),`;
+ const plain=value=>JSON.parse(JSON.stringify(value));
+ try {
+ await client.connect();
+ const library=adNetworksLibrary((sql,args)=>client.query(fixtures+sql.replace(/^with /,'')
+ .replaceAll('public.ad_network_publishers','fixture_publishers')
+ .replaceAll('public.ad_network_publisher_relationships','fixture_relationships')
+ .replaceAll('public.ad_networks','fixture_networks'),args));
+ const market=await library.loadAdNetworkDomainAgeStrip();
+ assert.equal(market.measured,4);
+ assert.deepEqual(plain(market.bins),[{year:2000,count:2},{year:2010,count:1},{year:2020,count:1}]);
+ assert.equal(market.median_year,2005);
+ assert.equal(market.oldest.domain,'a.example');
+ assert.equal(market.newest.domain,'c.example');
+ const networks=await library.loadAdNetworkDomainAgeByNetwork();
+ assert.deepEqual(Array.from(networks,n=>n.slug),['a','b']);
+ assert.deepEqual(plain(networks[0].strip.bins),[{year:2000,count:2},{year:2010,count:1}]);
+ assert.deepEqual(plain(networks[1].strip.bins),[{year:2000,count:1},{year:2020,count:1}]);
+ assert.deepEqual(Array.from(await library.loadAdNetworkDomainAgeByNetwork('food'),n=>n.strip.measured),[3,1]);
+ assert.equal((await library.loadAdNetworkDomainAgeStrip('b','food')).measured,1);
+ assert.equal(await library.loadAdNetworkDomainAgeStrip('empty'),null);
+ } finally {await client.end();}
+});
+
+test('weekly discovery SQL counts first discoveries once and hides weeks missing source attribution', {skip:!connectionString}, async()=>{
+ const {adNetworksLibrary}=await import('./loader-harness.mjs');
+ const client=new pg.Client({connectionString,connectionTimeoutMillis:15000,query_timeout:15000,
+ options:'-c default_transaction_read_only=on'});
+ const fixtures=`with fixture_clock as (
+ select date_trunc('week',now() at time zone 'UTC') at time zone 'UTC' as week_start
+ ), fixture_publishers(id,discovery_sources) as (values
+ (1,'[{"source_key":"scan"}]'::jsonb),(2,'[{"source_key":"checker"},{"source_key":"scan"}]'::jsonb),
+ (3,'[]'::jsonb),(4,'[{"source_key":"checker"}]'::jsonb),(5,'[{"source_key":"scan"}]'::jsonb),
+ (6,'[{"source_key":"scan"}]'::jsonb),(7,'[{"source_key":"scan"}]'::jsonb)),
+ fixture_events as (
+ select publisher_id,event,week_start+delta as observed_at from fixture_clock cross join (values
+ (1,'baseline','-100 days'::interval),(1,'newly_found','-6 days'::interval),
+ (1,'newly_found','-5 days'::interval),(2,'newly_found','-4 days'::interval),
+ (3,'newly_found','-13 days'::interval),(4,'newly_found','-12 days'::interval),
+ (5,'newly_found','-100 days'::interval),(5,'newly_found','-3 days'::interval),
+ (6,'newly_found','1 day'::interval),(7,'baseline','-3 days'::interval)
+ ) events(publisher_id,event,delta)
+ ),`;
+ try {
+ await client.connect();
+ const library=adNetworksLibrary((sql,args)=>client.query(fixtures+sql.replace(/^with /,'')
+ .replaceAll('public.ad_network_publishers','fixture_publishers')
+ .replaceAll('public.ad_network_relationship_events','fixture_events'),args));
+ const rows=JSON.parse(JSON.stringify(await library.loadAdNetworkWeeklyDiscoveries()));
+ const {week}=(await client.query(`select (date_trunc('week',now() at time zone 'UTC')-interval '7 days')::date::text as week`)).rows[0];
+ assert.deepEqual(rows,[{week,discovered:1,checker:1}]);
+ } finally {await client.end();}
+});
diff --git a/tests/pages/ad-networks/report.test.mjs b/tests/pages/ad-networks/report.test.mjs
index 776deb11..56d99ac1 100644
--- a/tests/pages/ad-networks/report.test.mjs
+++ b/tests/pages/ad-networks/report.test.mjs
@@ -10,6 +10,19 @@ import {targetsForEvents} from '../../../scripts/stack127/cache/targets.mjs';
import {networkIdentities} from '../../../scripts/ad-networks/network-identities.mjs';
const emptyCoverage={listed:1000,classified:0,traffic:0,age:0,platform:0,publisher:0,checked:1000,manager:0,niches:[],networks:[]};
+test('network and niche defaults agree between server and API while the directory stays A to Z',()=>{
+ const {defaultAdNetworkSitesQuery}=adNetworksLibrary(()=>{throw Error('Defaults must not query the database');});
+ for(const [network,niche] of [[null,null],[null,'food'],['mediavine',null],['mediavine','food']]) {
+ const params=new URLSearchParams();
+ if(network)params.set('network',network);
+ if(niche)params.set('niche',niche);
+ const query=defaultAdNetworkSitesQuery(network,niche);
+ assert.equal(query.sort,network||niche?'traffic':'domain');
+ assert.deepEqual(JSON.parse(JSON.stringify(query)),parseAdNetworkSitesParams(params));
+ params.set('sort','domain');assert.equal(parseAdNetworkSitesParams(params).sort,'domain');
+ params.set('sort','traffic');assert.equal(parseAdNetworkSitesParams(params).sort,'traffic');
+ }
+});
test('cold reports bound concurrent queries and release capacity after a database error',async()=>{
let active=0,maximum=0;
const {queryAdNetworkReport}=adNetworksLibrary(async(sql)=>{
@@ -25,6 +38,45 @@ test('cold reports bound concurrent queries and release capacity after a databas
assert.equal(results.filter(result=>result.status==='rejected').length,1);
assert.equal((await queryAdNetworkReport('after')).rows[0].value,'after');
});
+test('development serializes cold reports while retaining capacity after a failed query',async()=>{
+ let active=0,maximum=0;
+ const {queryAdNetworkReport}=adNetworksLibrary(async(sql)=>{
+ sql=sql.text;
+ active++;maximum=Math.max(maximum,active);
+ await new Promise(resolve=>setTimeout(resolve,5));
+ active--;
+ if(sql==='fail')throw Error('database failed');
+ return {rows:[]};
+ },{}, {process:{env:{NODE_ENV:'development'}}});
+ const results=await Promise.allSettled(['first','fail','last'].map(sql=>queryAdNetworkReport(sql)));
+ assert.equal(maximum,1);
+ assert.equal(active,0);
+ assert.equal(results.filter(result=>result.status==='rejected').length,1);
+ await queryAdNetworkReport('after');
+});
+test('simultaneous cold niche reports share reads and recover after a shared database failure',async()=>{
+ let counts=0,fail=true;
+ const library=adNetworksLibrary(async sql=>{
+ if(sql.includes('as classified')) {
+ counts++;
+ await new Promise(resolve=>setTimeout(resolve,5));
+ if(fail)throw Error('database failed');
+ return {rows:[{listed:0,confirmed:0,classified:0}]};
+ }
+ if(sql.includes('select niche,count(*)'))return {rows:[]};
+ if(sql.includes('as updated_at'))return {rows:[{updated_at:null}]};
+ if(sql.includes('r.verification_method as key'))return {rows:[]};
+ throw Error(`Unexpected SQL: ${sql}`);
+ });
+ const failed=await Promise.allSettled([library.getAdNetworkNichesPageData(),library.getAdNetworkNichesPageData()]);
+ assert.equal(counts,1);
+ assert.ok(failed.every(result=>result.status==='rejected'));
+ fail=false;
+ const [first,second]=await Promise.all([library.getAdNetworkNichesPageData(),library.getAdNetworkNichesPageData()]);
+ assert.equal(counts,2);
+ assert.deepEqual(first,second);
+ assert.equal(first.listed,0);
+});
test('niches need 100 classified sites and 80 percent scope coverage',()=>{
assert.equal(hasAdNetworkNicheCoverage(0,0),false);
assert.equal(hasAdNetworkNicheCoverage(99,99),false);
@@ -43,6 +95,10 @@ test('site controls disappear and reappear when their source fields fill',()=>{
for(const field of ['niche','traffic','domain_age','platform','publisher','manager','network'])assert.ok(full.availableColumns.includes(field));
assert.deepEqual(full.filters.niches.map(n=>n.slug),['food']);
assert.deepEqual(full.availableFilters,['niche','network']);
+ // A network with some unsorted sites still gets the niche column and filter.
+ const partial=adNetworkSiteAvailability({...emptyCoverage,listed:1000,classified:790,niches:['food']});
+ assert.ok(partial.availableColumns.includes('niche'));
+ assert.deepEqual(partial.availableFilters,['niche']);
});
const point=(date,listed=10)=>({date,listed,confirmed:listed,stale:0});
test('history excludes partial months, needs two real month ends, and handles leap days',()=>{
@@ -77,7 +133,7 @@ test('sites loader and parser default to 10, preserve explicit sizes, and bound
assert.deepEqual(JSON.parse(JSON.stringify(query)),parseAdNetworkSitesParams(new URLSearchParams()));
assert.equal(defaultAdNetworkSitesQuery('mediavine','food',50).pageSize,50);
assert.equal(defaultAdNetworkSitesQuery(null,'food').pageSize,10);
- const result=await loadAdNetworkSites({...query,sort:'traffic',page:99});
+ const result=await loadAdNetworkSites({...defaultAdNetworkSitesQuery('mediavine'),page:99});
assert.equal(result.effectiveSort,'domain');assert.equal(result.page,8);assert.equal(result.totalPages,8);
assert.deepEqual(Array.from(result.availableSorts),['domain','checked']);
const table=calls.find(c=>c.sql.includes('p.normalized_domain as domain'));
@@ -85,8 +141,33 @@ test('sites loader and parser default to 10, preserve explicit sizes, and bound
assert.deepEqual(Array.from(table.args).slice(-2),[10,70]);
const explicit=await loadAdNetworkSites({...query,page:99,pageSize:50});
assert.equal(explicit.pageSize,50);assert.equal(explicit.page,2);assert.equal(explicit.totalPages,2);
+ const niche=await loadAdNetworkSites(defaultAdNetworkSitesQuery(null,'tech'));
+ assert.equal(niche.effectiveSort,'domain');
assert.equal(parseAdNetworkSitesParams(new URLSearchParams('pageSize=50')).pageSize,50);
});
+test('default and explicit traffic sort use age, domain and id ties in both paging and final rows',async()=>{
+ const tables=[];
+ const {loadAdNetworkSites,defaultAdNetworkSitesQuery}=adNetworksLibrary(async(sql,args)=>{
+ if(sql.includes('as classified'))return {rows:[{...emptyCoverage,traffic:1000,age:1000}]};
+ if(sql.includes('select distinct n.slug')||sql.includes('select evidence,manager_relationships')||sql.includes('select slug,name,manager_domains'))return {rows:[]};
+ if(sql.includes('count(*)::int as total'))return {rows:[{total:75}]};
+ if(sql.includes('p.normalized_domain as domain')){tables.push({sql,args});return {rows:[]};}
+ throw Error(`Unexpected SQL: ${sql}`);
+ });
+ for(const query of [defaultAdNetworkSitesQuery('mediavine'),defaultAdNetworkSitesQuery(null,'tech')]) {
+ assert.equal((await loadAdNetworkSites(query)).effectiveSort,'traffic');
+ assert.equal((await loadAdNetworkSites({...query,sort:'traffic',page:2})).effectiveSort,'traffic');
+ }
+ const order="case p.traffic_group when 'top-1k' then 0 when 'top-10k' then 1 when 'top-100k' then 2 when 'top-1m' then 3 when 'not-ranked' then 4 else 5 end,p.domain_created_on asc nulls last,p.normalized_domain,p.id";
+ for(const {sql} of tables) {
+ assert.ok(sql.includes(`order by ${order} limit $4 offset $5`));
+ assert.ok(sql.trimEnd().endsWith(`order by ${order}`));
+ }
+ assert.deepEqual(Array.from(tables[0].args),['mediavine',null,'',10,0]);
+ assert.deepEqual(Array.from(tables[1].args),['mediavine',null,'',10,10]);
+ assert.deepEqual(Array.from(tables[2].args),[null,'tech','',10,0]);
+ assert.deepEqual(Array.from(tables[3].args),[null,'tech','',10,10]);
+});
test('an all-network data event refreshes every network, niches and both APIs',()=>{
const targets=targetsForEvents([{entity_type:'ad_networks',slug:'all'}]);
for(const network of networkIdentities)assert.ok(targets.verifyPaths.includes(`/ad-networks/${network.slug}`));
diff --git a/tests/pages/ad-networks/sites-sort-database.test.mjs b/tests/pages/ad-networks/sites-sort-database.test.mjs
new file mode 100644
index 00000000..c45a6ff7
--- /dev/null
+++ b/tests/pages/ad-networks/sites-sort-database.test.mjs
@@ -0,0 +1,43 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import pg from 'pg';
+import {adNetworksLibrary} from './loader-harness.mjs';
+
+// Read-only fixture query: no tables, temporary tables or public records are written.
+const connectionString=process.env.DATABASE_URL;
+test('traffic groups, oldest registrations, null dates and stable ties survive pagination', {skip:!connectionString}, async()=>{
+ let tableSql;
+ const library=adNetworksLibrary(async sql=>{
+ if(sql.includes('as classified'))return {rows:[{listed:20,classified:0,traffic:20,age:20,platform:0,publisher:0,checked:0,niches:[],networks:[]}]};
+ if(sql.includes('count(*)::int as total'))return {rows:[{total:20}]};
+ if(sql.startsWith('with matches as materialized'))tableSql=sql;
+ return {rows:[]};
+ });
+ await library.loadAdNetworkSites(library.defaultAdNetworkSitesQuery('mediavine'));
+ const pagingOrder=tableSql.match(/select p.id from matches p order by (.*?) limit \$4 offset \$5/s)[1];
+ const resultOrder=tableSql.slice(tableSql.lastIndexOf('order by '));
+ const site=(id,normalized_domain,traffic_group,domain_created_on)=>({id,normalized_domain,traffic_group,domain_created_on});
+ const rows=[
+ site(9,'a.com','top-1m','1980-01-01'),site(10,'a.com','not-ranked','1970-01-01'),
+ site(11,'a.com',null,'1960-01-01'),site(12,'b.com',null,null),
+ site(8,'a.com','top-100k','1980-01-01'),site(7,'a.com','top-10k',null),
+ site(6,'z.com','top-10k','2000-01-01'),site(5,'a.com','top-1k',null),
+ site(4,'a.com','top-1k','2020-01-01'),site(3,'same.com','top-1k','1990-01-01'),
+ site(2,'same.com','top-1k','1990-01-01'),site(1,'a.com','top-1k','1990-01-01'),
+ ];
+ const client=new pg.Client({connectionString,connectionTimeoutMillis:15000,
+ options:'-c default_transaction_read_only=on -c statement_timeout=15000'});
+ try {
+ await client.connect();
+ const sql=`with matches as materialized (
+ select * from jsonb_to_recordset($1::jsonb) p(id int,normalized_domain text,traffic_group text,domain_created_on date)
+ ), selected as materialized (
+ select p.id from matches p order by ${pagingOrder} limit $2 offset $3
+ ) select p.id from selected s join matches p on p.id=s.id ${resultOrder}`;
+ const page=async(size,offset)=>(await client.query(sql,[JSON.stringify(rows),size,offset])).rows.map(row=>row.id);
+ const expected=[1,2,3,4,5,6,7,8,9,10,11,12];
+ assert.deepEqual(await page(100,0),expected);
+ assert.deepEqual([...(await page(4,0)),...(await page(4,4)),...(await page(4,8))],expected);
+ assert.deepEqual(await page(4,12),[]);
+ } finally {await client.end();}
+});