# GHAN > GHAN is an audited cross-promotion and paid-install network for macOS and Windows desktop applications. Member apps promote each other inside templated in-app lifecycle slots and settle through a single append-only credit ledger. Every install is attributed by a single-use, expiring, cryptographically signed token — never by fingerprinting — and money only clears after the referred install is still in use 48 hours later. GHAN is MCP-first: a founder's coding agent can discover the network, register an app, read its own score with machine-readable rejection reasons, run campaigns and pull the raw signed ledger without ever opening the dashboard. The positioning claim the whole product is built to satisfy is "your agent can audit us" — every number GHAN publishes is reproducible from signed data a partner already holds. Last updated: 2026-09-22 ## Key facts - Desktop only: macOS (DMG) and Windows (EXE). No mobile, no web. - Placements are in-app lifecycle slots — install complete, first success, update, idle, uninstall intent. Never inside an installer, which is the mistake that killed the previous generation of desktop bundling networks. - Creatives are templated: partner icon, partner name, one generated line, rendered by GHAN's own SDK. Partners cannot ship custom HTML or images into another app. - Attribution is deterministic only: ed25519-signed, single-use tokens that expire 15 minutes after issue. No device fingerprinting and no probabilistic matching, ever. - Every monetised event carries two independent signatures, one from the serving app and one from the receiving app. A chain cannot advance past install_claim with only one. - Payout clears on behaviour, not on events: a standard install clears after 48 hours of retention, and any pair trading above EUR 500 per day clears on day-7 engagement instead. - Rate card per cleared install is a published FLOOR, not a ceiling: utilities and consumer EUR 12-18, creator tools EUR 20-30, prosumer and B2B EUR 35-50. The floor never rises and any approved advertiser can always buy at it. - Above the floor there is an optional second-price auction for priority in contested inventory. You pay one cent above the next-highest competing bid, never your own maximum, and 30 percent of every category is reserved at floor and never auctioned. You bid per cleared install, not per click. - Nine security layers sit between a member app and a bad install: the gate, the placement constraints, attribution, device signals, economics, behaviour, enforcement, data, and disclosure. - GHAN keeps 30 percent. The serving app earns 70 percent of the CPI, multiplied by 1.2 when taken as network credits instead of cash. - The ledger is append-only at the database level: UPDATE, DELETE and TRUNCATE are blocked by trigger, and every line is retrievable over MCP with its event-chain reference. - Vetting gate before any app can trade: notarisation or Authenticode signature, a clean VirusTotal result, domain age of at least six months, a verified contact email, and a download URL that actually serves the declared bundle id. --- # About GHAN URL: https://ghan.io/about/ Updated: 2026-09-22 GHAN is built by Daniel Matalon. It exists because desktop software has no distribution layer and the last people who tried to build one destroyed the category — so the interesting problem is not the marketplace, it is the referee. ## Why a referee and not a marketplace The idea that desktop apps should promote each other is obvious and old. It has been tried repeatedly and it has failed repeatedly, and it never failed because the matching was bad. It failed because nobody could tell whether the installs were real, so the cheapest way to earn was always to manufacture them, and the networks that tolerated that out-competed the ones that did not until antivirus vendors ended the argument for everybody. So GHAN's product is not the matching. It is the proof. - A unit of account that is expensive to fake: two independent signatures plus 48 hours of survival. - A ledger neither party can edit, where both parties signed every line. - A gate that is automated, public and re-run weekly. - Published rejection numbers, because a network with no fraud report is a network you cannot evaluate. ## The seven principles 1. **Deterministic attribution only.** Signed, single-use, expiring tokens. No fingerprinting or probabilistic matching, ever. 2. **Payout clears on behaviour, not events.** An install is not money. 48-hour retention clears standard installs; day-7 engagement clears anything above EUR 500 per day per pair. 3. **Cost-to-fake exceeds payout** on every monetised event. A feature that breaks this inequality does not get built. 4. **Templated creatives only.** Icon, name, one generated line, rendered by GHAN's SDK. No custom banners, no partner HTML. 5. **Two human moments, never zero.** The partner ships the release containing the SDK in their own signed build, and the partner authorises money. Everything else is agent to agent. 6. **MCP-first.** Every write capability ships in the MCP server before, or instead of, the dashboard. The dashboard is a read-only mirror plus billing. 7. **Transparency structural, not promised.** One ledger, both parties signed, machine-readable statements over MCP. These have already cost the product features. Installer-time placements, custom creative, probabilistic attribution and direct app-to-app targeting were all removed by principle 3 alone. ## What GHAN has deliberately not built - No mobile. Not now, not later. - No pure auction, and no enterprise tier. The rate card is a published floor that never rises; bidding above it buys priority, never access. - No custom creative surface. - No installer-time placement. - No native Swift or C# SDK yet — version 1 is Electron, Tauri and Node, and the roadmap says so rather than implying otherwise. ## The person GHAN is built by **Daniel Matalon**. Public profile: [linkedin.com/in/dmatalon](https://www.linkedin.com/in/dmatalon/). Reach the project at `hello@ghan.io` or through the [contact page](/contact/). A network selling auditability with an anonymous team would be its own counterexample. ## Who is behind GHAN? GHAN is built by Daniel Matalon, who also builds Boom and Recepte. Contact is hello@ghan.io and the founder's public profile is linked from this page. There is no anonymous team behind a brand name, which matters for a network whose entire pitch is auditability. ## Why build this now? Because two things changed at once. Desktop software is being written again at volume, largely in Electron and Tauri by very small teams, and those teams now have coding agents that can integrate an SDK, read a score and operate a campaign without a human. A network that is MCP-first can onboard a partner in an afternoon instead of a quarter, and that is the only way a fixed-rate network with a strict gate reaches enough members to be useful. ## What are GHAN's non-negotiable principles? Seven, written down and treated as constraints rather than aspirations. Deterministic attribution only. Payout clears on behaviour, not events. Cost to fake must exceed the payout on every monetised event. Templated creatives only. Two human moments, never zero. MCP-first for every write capability. Transparency that is structural rather than promised. ## Is GHAN funded? GHAN is self-funded and in its founding-partner phase. There are no investor-driven growth targets pushing against the gate, which is relevant because every previous network in this category loosened its standards under exactly that pressure. --- # Deterministic attribution, and why GHAN refuses fingerprinting URL: https://ghan.io/attribution/ Updated: 2026-09-22 GHAN attributes an install only when a single-use, unexpired, signed token is presented by the receiving app and countersigned with its own key. There is no fingerprinting fallback, and an install that cannot prove itself is simply not attributed. ## The rule > An install is attributed if and only if a single-use, unexpired, server-signed token is presented by the receiving SDK and countersigned with that SDK's own ed25519 key. There is no second mechanism. Everything below is the consequence of that sentence. ## The token | Property | Value | Enforced by | |---|---|---| | Issued at | Click time, server side | `tokens` table row | | Lifetime | 15 minutes | `expires_at`, checked server side | | Uses | Exactly one | Unique constraint on `used_at` | | Nonce | Per token | Column, generated server side | | Binding | Campaign + serving app | Foreign keys on the token row | Single use is enforced by a database constraint, not by an `if` statement, because an `if` statement has a race condition and a unique index does not. ## The two signatures A GHAN event carries up to three signatures, and the monetised transition requires two of them to be independent: - `sig_serving` — produced by the SDK inside the app that rendered the card - `sig_receiving` — produced by the SDK inside the app that was installed - `server_sig` — produced by GHAN, which proves GHAN saw it, and proves nothing about whether it happened A chain cannot advance past `install_claim` without both `sig_serving` and `sig_receiving`. Neither app can produce the other's signature, because each private key was generated on the end user's machine on first run and never left it. This is the structural reason GHAN's numbers are checkable: for any install you were billed for, you personally hold one of the two signatures that made it billable. ## What GHAN deliberately gives up Refusing probabilistic attribution is not free. It costs: - **Attributed volume.** Installs that took the long route are invisible, and the serving app earns nothing for them. - **Cross-device journeys.** Download on a work laptop, install on a home machine, and the chain correctly does not exist. - **Comparability.** A mobile MMP will report higher attribution rates than GHAN for the same traffic, because it is counting things GHAN refuses to count. The alternative is a network where the easiest way to earn is to make weak signals look strong. Every monetised feature in GHAN has to pass one test — the cost of faking it must exceed the payout for it — and a probabilistic fallback fails that test on the first line. ## What is collected, and what is not Attached to an install claim: - Virtual machine and hypervisor indicators - Operating-system install age - A **salted** hardware hash, never the raw identifier - Clock skew against the server - The claiming IP's country and autonomous system, resolved from an offline database so the address itself never leaves GHAN's infrastructure on the hot path Not collected, ever: - File names, file contents, window titles, clipboard, keystrokes - Raw hardware identifiers, MAC addresses, serial numbers - Advertising identifiers or any cross-app identity - Any personally identifying information at all The device signals exist to kill fraudulent chains, not to identify people, and they are strictly worse at identifying people than the fingerprinting GHAN refuses to do. That is the intended ordering. ## Consent The SDK ships a consent-safe mode. The host application passes its own consent state, and no telemetry at all is emitted before consent is true. A GHAN card can still render — rendering a templated card is not processing personal data — but nothing is measured until the person has agreed to measurement. See [security and privacy](/security/). ## What is deterministic attribution? Deterministic attribution means an install is credited to a source only when a unique identifier issued at click time is presented back at install time and verified. The alternative, probabilistic attribution, infers the match from signals like IP address, screen resolution, operating system version and timing. Deterministic attribution either proves the link or admits it cannot; probabilistic attribution always produces an answer, including when there is nothing to find. ## Why not use fingerprinting as a fallback? Because a fallback is not a safety net, it is the attack surface. The moment a network will credit an install on IP-plus-timestamp similarity, the cheapest way to earn is to generate plausible similarity at scale, and every fraud rule downstream is then arguing with a system that was designed to say yes. Refusing the fallback costs GHAN attributable volume and buys the one property the network is sold on. ## How does the token survive a browser download and a manual install? Two paths, both deterministic. The click registers a ghan:// protocol handler invocation carrying the token, and the same token is written to a small handoff file in a known location. The receiving SDK checks both on first run. If a person downloads on one machine and installs on another, neither path finds the token and the install is correctly not attributed. ## What is the token expiry and why 15 minutes? Fifteen minutes from issue, enforced server-side, with single use enforced by a unique constraint in the database rather than by application logic. Fifteen minutes is long enough for a normal download-and-install on a normal connection and short enough that a harvested token is worthless by the time it could be resold. ## What percentage of installs go unattributed? GHAN expects a meaningful share of real installs to go unattributed - people who download now and install tomorrow, people who move the installer to another machine, people behind restrictive protocol-handler policies. Those installs are free for the advertiser and earn the serving app nothing. Undercounting is the deliberate side of the trade. --- # Bidding above the floor URL: https://ghan.io/bidding/ Updated: 2026-09-22 A fixed price cannot clear a market. GHAN therefore prices in two layers: a published floor anyone can always buy at, which never rises, and a second-price auction above it for priority when inventory is contested. You bid a price per retained install, not per click. ## The problem with a purely fixed price The original rate card was fixed, published and unchangeable. That solved one real problem and created another. It solved being priced out. In a search auction the clearing price *is* the price. When a better-funded competitor enters your keyword, the floor rises under you and eventually you cannot buy at all. That is the [arithmetic](/compare/google-ads/) that pushes one-time-licence desktop apps out of paid search entirely. But a fixed price cannot clear a market. If three advertisers want creator-tool inventory and there is only enough for two, a fixed price has no way to decide, and it systematically underpays the apps supplying that inventory. Supply then does not grow, because supplying more earns no more. A price that never responds to demand is not a protection, it is a cap on the whole network. ## Two layers | Layer | What it does | Who sets it | |---|---|---| | **Floor** | The published rate card. Any approved advertiser can always buy at it. It never rises. | GHAN, published in code | | **Bid** | Optional. Buys priority in contested inventory, above the floor. | The market | You do not have to participate in the second layer. Leave the bid unset and you buy at floor price, forever, at the price on the [pricing page](/pricing/). ## How the auction works **Second price.** You set `max_bid_cents` — the most you are willing to pay for a cleared install in that category. If you win, **you pay one cent more than the next-highest competing bid**, never your own maximum. That single property is what removes the objection to auctions. Under second-price clearing, bidding your honest value is the best strategy available to you. There is no gain from watching competitors, no gain from re-bidding, and no spiral, because the thing you are competing against is somebody else's honest value rather than their nerve. **Per category, per slot type.** There is no single global auction. Contention is resolved inside a category band for a given [lifecycle slot](/lifecycle-slots/), because a `first_success` impression in a creator tool is a different asset from an `idle` impression in a utility. **On cleared installs, not clicks.** This is the difference that matters most. A bid is a price for an install that is *still in use 48 hours later*. If the install does not survive, you pay nothing regardless of what you bid. You cannot lose money to a high bid on traffic that never converts, which is the normal way an auction hurts you. ### A worked example Creator tools, floor EUR 24. Three advertisers want the same contested impression: | Advertiser | Max bid | Outcome | |---|---|---| | A | EUR 41 | **Wins.** Pays EUR 33.01 | | B | EUR 33 | Loses this impression | | C | unset (floor buyer) | Buys from the reserved tranche at EUR 24 | A bid 41 and paid 33.01 — one cent above B. A's honest maximum cost them nothing extra. C never entered the auction and still bought at 24. The serving app earns 70 percent of **33.01**, not of 24. That is the market doing its job: the app that supplied a contested placement captured the contention. ## The three protections that stay Bidding is added on top of the guarantees, not instead of them. **1. The floor never rises.** It is a published number in `packages/shared/ratecard.ts`, changed only as a versioned change announced in the [changelog](/changelog/) before it takes effect. No amount of bidding moves it. This is the whole of what "never enter an auction" was protecting, and it is intact. **2. Thirty percent is reserved.** In every category, 30 percent of inventory is sold only at floor price and is never auctioned. It is allocated round-robin among approved floor-price advertisers. A bidder with unlimited money wins priority in the contested 70 percent and cannot touch the reserved 30. **3. Pair caps still bind.** Net flow between any two apps stays capped at EUR 500 per month until both have behaviour scores, and clearing above EUR 500 per day per pair still moves to day-7 engagement. A bid cannot buy its way out of a [fraud control](/fraud-prevention/). ## Why this is not the thing that broke search advertising The objection to auctions in the [original manifesto](/manifesto/) was real but imprecisely aimed. Stated properly, there are four things wrong with the search auction for a small desktop app, and bidding is only implicated in one of them: | The actual problem | Present on GHAN? | |---|---| | The clearing price is the only price — no floor to fall back to | **No.** The floor is guaranteed and permanent | | You bid per click, and pay whether or not anything happens | **No.** You bid per cleared install | | First-price dynamics reward nerve over value | **No.** Second price | | A funded competitor can take 100% of your category | **No.** 30% reserved at floor | Price discovery was never the problem. Price discovery with no floor, on the wrong unit, with the wrong clearing rule, was. ## Setting a bid ``` create_campaign { app_id: "app_...", categories: ["creator_tools"], daily_budget_cents: 20000, max_bid_cents: 4100 // optional; omit to buy at floor } ``` `max_bid_cents` must be at or above the category floor. Omit it and the campaign is a floor-price campaign. Change it at any time; it takes effect on the next placement fetch. `get_stats` reports `avg_clearing_price_cents` alongside the floor, so you can always see what contention actually cost you — and see when it cost you nothing, which for most categories most of the time is the expected answer. ## For the apps serving placements You earn 70 percent of the price that cleared, not 70 percent of the floor — or 84 percent of it in value if you take [credits](/pricing/). This is the half of the argument that makes the market worth having. Under a purely fixed price, an app with genuinely valuable inventory — high retention, high-intent moments, a category people want — earned exactly the same as an app with poor inventory. There was no mechanism by which being good at this paid more, and therefore no mechanism by which the network grew the supply it most needed. ## Does GHAN have an auction? Partly, and deliberately. The rate card is a floor that any approved advertiser can always buy at, and that floor never rises. Above the floor there is a second-price auction that decides who gets priority when more advertisers want a category's inventory than there is inventory. So the price discovery is a real market and the access guarantee is not auctioned away. ## How is this different from the Google Ads auction? Three differences, and they are the ones that matter. First, there is a floor you can always buy at - in a search auction the clearing price is the floor, so when a better-funded competitor enters your keyword you are priced out entirely. Second, you bid per cleared install rather than per click, so a bid is a price for a user still using your software two days later. Third, a reserved share of every category's inventory only ever sells at floor price, so a funded bidder cannot take all of it at any price. ## Can a well-funded app outbid me and take all the inventory? No. Thirty percent of every category's inventory is reserved for floor-price buyers and is never auctioned, allocated round-robin among approved advertisers. Pair caps still apply on top of that. A bidder with unlimited money can win priority in the contested seventy percent and cannot touch the rest. ## What is second-price clearing? You set the most you are willing to pay. If you win, you pay one cent more than the next-highest competing bid, not your own maximum. The consequence is that bidding your true value is the best strategy available to you, and there is no advantage in watching competitors and re-bidding. It is the mechanism that removes the panic-bidding spiral, which was the real objection to auctions in the first place. ## Do I have to bid? No. Leave max_bid_cents unset and you buy at floor price forever, out of the reserved tranche and out of whatever contested inventory nobody bid on. Most members are expected to never set a bid. ## What happens to the serving app's earnings when a bid clears above the floor? The serving app earns 70 percent of the price that actually cleared, not 70 percent of the floor. That is the point of having a market at all - when demand for a category rises, the apps supplying that inventory are the ones who capture it, which is what makes more of them supply it. ## Why was GHAN originally designed without bidding? Because the first version of the spec treated every auction as the thing that broke desktop advertising. That was half right. What breaks a one-time-licence app is not price discovery, it is that the auction clearing price becomes the only price, so the floor rises until you cannot buy at all. Separating the floor from the discovery keeps the protection and restores the market. --- # Onboarding built for the agent, not the buyer URL: https://ghan.io/blog/agent-first-saas-onboarding/ Updated: 2026-09-22 If the person integrating your product is a coding agent, then your onboarding is a tool schema, your error messages are enum values, and your documentation is something returned by a function call. Most B2B products are still built as though a human will read a pricing page and book a demo. ## The integrator changed For a developer tool in 2026, the entity that reads your documentation, evaluates your pricing and writes your integration is frequently not a person. It is a coding agent, working from a one-line instruction like "add cross-promotion to this app." That agent has a specific set of capabilities and a specific set of frustrations. It can read a JSON schema perfectly and a marketing page badly. It can follow a tool sequence reliably and a "contact sales" link not at all. It will parse your error message with a regular expression and get it wrong when you improve the wording. Most B2B onboarding is still built for a buyer who will read a pricing page, book a demo, receive a sandbox key and forward it to an engineer. That flow takes a week. The agent flow takes four minutes, and the products that support it will be integrated in situations where the products that do not never get evaluated. ## What building for it actually involves **Ship the tool before the screen.** If a capability exists only as a dashboard form, an agent cannot use it, and adding an API later means two implementations that disagree. Building the tool first and letting the dashboard call the same thing costs nothing extra and avoids the divergence entirely. **Publish prices as a function.** `get_rate_card {}` returning structured data, unauthenticated, is worth more than any pricing page. An agent evaluating three vendors will silently drop the two that require a conversation. **Return your documentation from a tool.** `get_integration_guide {}` returns the current guide as markdown. The agent gets the authoritative version at the moment of use instead of scraping a page that may be cached, may be stale, and may be for a different major version. **Make rejections machine-actionable.** `gate_domain_too_young` with an eligibility date is something an agent can schedule around. "Unfortunately your domain does not meet our requirements at this time" is something it can only give up on. **Leave a diff, not instructions.** `npx @ghan/sdk init` writes the wiring and leaves a reviewable change. It does not commit, because the human still has to look. ## The two moments that should stay human Full automation is available and is the wrong target. Two decisions should require a person, and naming them explicitly is what makes automating everything else defensible: **Shipping the release.** Third-party code entering a binary you sign is a decision about what your signature means. An agent can prepare it; a person should approve it. **Authorising money.** Not each payment — a ceiling, set once, inside which an agent spends freely. The ceiling is the human decision and the spending is not. Every other step — registration, scoring, integration, campaign creation, budget changes, ledger reads, payout requests — is better done by an agent, and in [GHAN](/) it is. ## What this costs Building MCP-first means the dashboard arrives late and looks sparse, because it is a mirror rather than the product. Publishing prices as a function means losing the negotiation. Returning reason codes means your rejections are legible to competitors as well as to partners. Those are real costs. They are smaller than the cost of being the vendor an agent could not evaluate. ## What does MCP-first mean? That every write capability ships as an MCP tool before, or instead of, a dashboard screen. The dashboard becomes a read-only mirror plus billing rather than the primary interface. In practice it changes what you build first - a tool schema rather than a form, an enum of rejection reasons rather than a support article, and a function that returns the integration guide rather than a documentation site an agent has to scrape. ## Should everything be automated? No, and picking the exceptions deliberately matters more than the automation. Two moments should stay human - shipping a release that contains third-party code, which is a decision about what you put your signature on, and authorising money, which is a decision about risk. Automating either one would be technically straightforward and would remove the accountability that makes the rest safe. ## Why return error codes instead of messages? Because an agent acting on a rejection needs to branch, and branching on English is unreliable and silently version-dependent. A stable code with an unstable human-readable string beside it gives both audiences what they need. The code is the contract; the sentence is a courtesy. --- # Desktop distribution is broken, and the auction is why URL: https://ghan.io/blog/desktop-distribution-is-broken/ Updated: 2026-09-22 A desktop app selling a EUR 29 one-time licence is bidding for the same click as a product billing EUR 29 every month. The second one can profitably pay about twelve times more. That is not a creative problem or a landing page problem; it is arithmetic, and no channel expertise fixes it. ## The number that ends the conversation | | One-time licence | Monthly subscription | |---|---|---| | Price | EUR 29 once | EUR 29 per month | | Gross lifetime value | ~EUR 29 | ~EUR 350 at 12 months | | Affordable customer acquisition cost at 30% margin | ~EUR 9 | ~EUR 105 | | Clicks per customer at 3% conversion | 33 | 33 | | Affordable cost per click | **EUR 0.27** | **EUR 3.18** | Both are bidding on "best screen recorder for mac". One can pay nearly twelve times more for the identical click. There is no creative, no landing page and no bid strategy that closes a twelve-fold gap, because the gap is not in the advertising. It is in the pricing model. An auction is a mechanism for discovering who values a thing most. It works exactly as designed. The uncomfortable conclusion is that for a one-time-licence desktop app, working as designed means you lose. ## What people try instead, and why each one stalls **Content and SEO.** Genuinely works, and takes eighteen months. It is also increasingly mediated by AI answers rather than blue links, which changes what "ranking" means without removing the eighteen months. **Communities.** Works once. Launch on Hacker News, get a spike, and discover that the spike is not a channel. Communities reward novelty, and your app is only novel for one week of its life. **Affiliates and deal sites.** Works, and prices your product at 50 percent off forever. The discount is not the cost; the anchor is. **Curated bundles.** A real distribution surface, and the only browsable shelf desktop software has. You give up the customer relationship for it, which for some apps is the right trade and for others is the whole business. **The app stores.** The Mac App Store is a sandbox tax and a discovery surface people do not browse. The Microsoft Store is worse. ## The asset nobody counts Every desktop app has an audience of people who have proven, within living memory, that they will download and install desktop software. That is an extraordinarily specific behaviour. Roughly nobody in the general population did it this month, and everybody in your user base did it at least once. Advertising exists to find those people. You already have them. The reason this has not been turned into a channel is not that nobody thought of it. It is that every previous attempt monetised the wrong moment, paid on the wrong event, and gave partners the wrong amount of control — and got the entire category classified as malware for it. That history is the subject of [the next piece](/blog/why-install-networks-die/). ## What has to be true for the trade to work For an app to be willing to show another app's card, three things have to hold: 1. **The moment cannot be hostile.** After install, inside the product, at a moment the host app chose. Never inside an installer, never in competition with a Next button. 2. **The unit has to be honest.** Paying on the install event means the seller's incentive is volume regardless of fit. Paying on retention at 48 hours means an irrelevant card earns nothing. 3. **The count has to be checkable.** If the network reports the numbers and both sides have to believe it, the network will eventually be wrong in its own favour. Two independent signatures per billed line removes the question. Those three constraints are the whole of [GHAN's](/) design, and they read as arbitrary until you know which specific failure each one is a response to. ## Why can't desktop apps compete in ad auctions? Because an auction prices a click by what it is worth to the bidder who values it most, and in nearly every software category that is a subscription product with an order of magnitude more lifetime value per customer. A one-time licence is not outbid because its ads are worse; it is outbid because its revenue model produces less money per customer, and the auction is a mechanism for discovering exactly that. ## What should a desktop app do instead? Use channels whose price is not set by an auction. Earned distribution through communities and content is the obvious one and the slowest. Curated bundles trade the customer relationship for a shelf. Cross-promotion trades attention you already have for installs at a fixed published rate, which is the only paid channel whose price does not move when a better-funded competitor enters your category. --- # Writing about desktop app distribution URL: https://ghan.io/blog/ Updated: 2026-09-22 Long-form writing on the economics and mechanics of desktop distribution. Each piece argues a position rather than summarising a topic, and each one is also available as markdown and in the RSS feed. ## Articles - [Desktop distribution is broken, and the auction is why](/blog/desktop-distribution-is-broken/) — the arithmetic that stops a one-time-licence app from buying its own users. - [Every install network dies the same way](/blog/why-install-networks-die/) — three mechanisms, one outcome, and what has to change structurally. - [Onboarding built for the agent, not the buyer](/blog/agent-first-saas-onboarding/) — what MCP-first actually means when a partner's coding agent is the integrator. Subscribe via [RSS](/feed.xml). Everything is also in [llms-full.txt](/llms-full.txt). ## Is there a feed? Yes, RSS at /feed.xml, declared in the head of every page. It carries both articles and changelog entries. --- # Every install network dies the same way URL: https://ghan.io/blog/why-install-networks-die/ Updated: 2026-09-22 The desktop cross-promotion category has a graveyard, and the causes of death are not mysterious. Three mechanisms, each individually reasonable, combine into an incentive structure whose profitable endpoint is software people did not choose. Removing any one of the three breaks the chain. ## Three mechanisms ### 1. The offer lives inside the installer An installer is a sequence of screens whose only purpose is to be clicked through. The person has already decided; they are executing. A third-party offer placed in that sequence competes for the same reflexive click as Next. That means every increment of ambiguity between "continue" and "accept" is worth money. Not because anyone set out to deceive, but because A/B testing finds it. The variant that converts better is the one that is slightly less clear, and the process runs until the offer is indistinguishable from a system dialog. There is no equilibrium here where maximum clarity is also maximum revenue. ### 2. The money clears on the install event If payment happens the moment software lands on a disk, then retention, satisfaction and relevance are all somebody else's problem. A brilliant match and a mistaken click pay identically. A rational publisher facing that rule optimises for the number of things that land, and the cheapest way to increase that number is never better targeting. ### 3. The partner supplies the creative A network that transmits arbitrary partner content is a distribution channel for arbitrary partner content. Whatever the review process, the pressure runs one direction: big advertisers want custom treatments, custom treatments look more native, more native converts better, and eventually the thing being distributed is not an advertisement. ## How it ended Antivirus vendors do not evaluate intent. They classify behaviour, and the behaviour — software arriving on machines through an install flow the person did not deliberately choose — is the behaviour of a potentially unwanted program. Crucially, the classification attaches to the **SDK**, not to individual offers. So the honest integrator who carefully explained every offer got flagged alongside the worst actor in the network. By 2015 that was most of the category. OpenCandy shut down in 2016. AdDuplex, the cleanest attempt, shut down quietly in 2023. The lesson usually drawn — "desktop cross-promotion does not work" — is the wrong one. The correct lesson is that those three mechanisms do not work, and every one of them is optional. ## What removing them costs Removing them is not free, which is why nobody did. - **No installer placement** means giving up the highest-volume, highest-attention inventory on desktop. - **No payment on the event** means the network carries 48 hours of settlement risk and reports lower conversion numbers than a competitor who does not. - **No partner creative** means losing every advertiser whose brand team requires control, which is most large advertisers. A network that removes all three has worse unit economics on day one than one that does not. It only wins if the thing it is selling is trust, and trust only becomes a product if it is checkable. ## Checkable, specifically Promising to behave is what the previous generation also did. The difference has to be structural: - The unit of billing requires two independent cryptographic signatures, one of which is produced inside the advertiser's own signed binary. - The ledger blocks edits at the database level, so corrections are new lines and history survives. - The gate is automated, published, and re-run weekly rather than at onboarding. - Rejection numbers are published, because a network reporting zero fraud is reporting on its own detection, not on reality. None of those are promises. They are properties a partner's agent can verify without the network's cooperation, which is the only kind of trust claim that survives revenue pressure. That is what [GHAN](/) is, and the constraints on its [lifecycle slots](/lifecycle-slots/) and its [fraud rules](/fraud-prevention/) are each traceable to one of the three mechanisms above. ## What killed OpenCandy? The combination of placing an offer inside an installer and paying on the install event. Individually each is defensible. Together they make accidental acceptance the most profitable outcome, and there is no stable point at which the clearest possible presentation is also the best-earning one. Antivirus vendors classified the resulting behaviour correctly, and the classification attached to the SDK rather than to individual offers. ## Can a cross-promotion network be safe? Yes, if the three mechanisms are removed rather than moderated. No placement inside an installer. No payment on the install event. No partner-supplied creative. A network that keeps any of the three and promises to behave has only moved the failure from its design into its governance, and governance is exactly what degrades under revenue pressure. --- # GHAN changelog URL: https://ghan.io/changelog/ Updated: 2026-09-22 What shipped, when. Every entry corresponds to something a partner could in principle verify, and the feed is available as RSS at /feed.xml for agents and readers who would rather be told than check. ## 2026-09-22 — Machine-readable site The whole of ghan.io rebuilt as server-rendered static pages with a markdown twin for every URL, a connected JSON-LD graph, `llms.txt` and `llms-full.txt`, an OpenAPI document, and the agent-discovery files at `/.well-known/`. Content negotiation returns `text/markdown` to any agent that asks for it. Affects: [docs](/docs/), [llms.txt](/llms.txt). ## 2026-09-22 — Supabase live, ledger proven on the real database Core schema and the append-only ledger triggers applied to a production Postgres instance. A test suite runs the migration against a real Postgres 16 and proves `UPDATE`, `DELETE` and `TRUNCATE` on `ledger` all fail. Row-level security enabled everywhere and the public API roles revoked, closing a PostgREST exposure found during the same session. Affects: [transparency](/transparency/), [how it works](/how-it-works/). ## 2026-09-22 — Stripe sandbox wired Connect Express onboarding and platform payment configuration in sandbox, with a statement descriptor suffix so a charge from GHAN is recognisable on a partner's statement. Affects: [pricing](/pricing/). ## 2026-09-21 — Offline geo and datacenter detection Geo and ASN lookups moved to an offline MaxMind-format database, so no partner IP address leaves GHAN's infrastructure on the hot path. Datacenter detection is approximated from the autonomous system owner with a deliberately conservative allowlist, because a false positive silently discards a real install and costs a partner money. Affects: [fraud prevention](/fraud-prevention/), [attribution](/attribution/). ## 2026-09-21 — Signing and rate card ed25519 signing with canonical JSON serialisation, and the rate card as versioned code published through `get_rate_card`. Affects: [pricing](/pricing/), [docs/mcp](/docs/mcp/). ## 2026-09-20 — Monorepo scaffold API, MCP server, jobs and dashboard applications scaffolded; shared package for schemas, event types, signing and the rate card; forward-only SQL migrations with a runner that refuses to proceed if an applied migration's checksum changed. Affects: [status](/status/). ## Is there an RSS feed? Yes, at /feed.xml, declared in the head of every page on this site so an agent or a reader can discover it without being told. It carries changelog entries and articles. ## How often is this updated? Whenever something ships. GHAN is pre-launch and moving quickly, so entries are currently weekly or more often. --- # GHAN vs. affiliate networks for desktop software URL: https://ghan.io/compare/affiliate-networks/ Updated: 2026-09-22 An affiliate network pays a commission when someone buys, usually attributed by a cookie and usually alongside a discount code. A cross-promotion network pays a fixed amount when someone installs and keeps using your software. The difference in what is being bought changes almost everything downstream. ## The core difference | | Affiliate network | Cross-promotion (GHAN) | |---|---|---| | **Paid on** | A sale | An install still in use at 48 hours | | **Typical cost** | 20–40% of revenue, recurring for some programs | From EUR 12–50 once, floor price | | **Attribution** | Cookie, last click, 30–90 day window | Single-use signed token, 15-minute expiry, two signatures | | **Who writes the creative** | The affiliate | Nobody — templated card | | **Discounting** | Usually expected, often required | Never involved | | **Who the traffic is** | Coupon sites, reviewers, YouTubers, communities | Users of other desktop apps, at install time | | **Brand risk** | Real — affiliates say what they like | Structurally low — no partner copy exists | | **Common fraud** | Cookie stuffing, last-click hijack, brand bidding | Install farms, emulators, token replay | | **You can pay in** | Money only | Money, or attention you already have | ## The cost nobody puts in the spreadsheet A 30 percent commission on a EUR 49 licence is EUR 14.70, which looks competitive against a cross-promotion CPI in the same range. But for desktop software, most affiliate volume arrives through coupon and deal sites. That means a discount on top of the commission, so the real figure is closer to EUR 14.70 plus 20 to 40 percent off the price. And the discount does not end when the campaign does. Once "[your app] coupon" is a search result with answers, your effective price is the discounted one permanently. The commission is the visible cost. The price anchor is the one that compounds. ## Attribution: cookies versus tokens Affiliate attribution is a cookie, and cookies have three well-known problems: they expire, they are blocked, and they can be written by anyone who can get a browser to load a URL. That last one is why the most common affiliate fraud is not fake sales but **stolen credit** — a browser extension injecting an affiliate cookie at checkout on a purchase the customer was already making, or an affiliate bidding on your own brand name to intercept traffic that was already yours. The conversion is completely genuine. Only the attribution is theft, which makes it much harder to detect than a fake install. GHAN's attribution is a single-use token that expires in 15 minutes and must be countersigned by the receiving application's own key. That does not make GHAN better than an affiliate program — it makes the fraud different. Ours is manufactured volume, and it is caught with [retention, device signals and cohort shape](/fraud-prevention/). Theirs is stolen credit, and it is caught by auditing your own affiliates, which most programs do not do. ## When an affiliate program is the right answer - You have real margin and can absorb a commission plus a discount. - Your buyers research before purchasing, so reviewers and comparison sites genuinely influence them. - You have a recognisable product that creators want to talk about. - You can afford to police brand bidding and coupon extensions, which is the actual work of running one. ## When cross-promotion is the right answer - Your price point cannot support a commission plus a discount. - You would rather pay in attention than in cash. - You do not want anyone else writing copy about your product. - You want a published floor price rather than a percentage of a sale you have not made yet. ## Running both There is no conflict. Affiliates reach purchase intent; cross-promotion reaches people who are installing desktop software right now and were not looking for you. Measure them on the same basis, which for desktop software means **cost per retained customer** — affiliate commission plus the discount given, divided by customers still active at your retention horizon, against the [rate card](/pricing/), which is already a retained price. Comparing a commission percentage to a CPI directly will mislead you in whichever direction your instinct already leans. ## Are affiliate programs good for desktop software? They work, and they cost more than the commission rate suggests. A 30 percent commission on a EUR 49 licence is EUR 14.70, which is comparable to a cross-promotion CPI - but most affiliate traffic for desktop software comes through coupon and deal sites, which means a discount on top of the commission and, more importantly, a permanent change to what your product appears to be worth. The commission is the visible cost. The price anchor is the real one. ## How is cross-promotion different from an affiliate program? An affiliate is paid on a sale; a cross-promotion network is paid on a retained install. That single difference cascades. Affiliate attribution is usually a cookie, which is fragile and contestable; cross-promotion here uses a signed single-use token. Affiliates choose their own creative and messaging, which is why brand-safety complaints dominate affiliate management; cross-promotion cards are templated. And affiliates are usually incentivised to discount, while a fixed CPI is indifferent to your pricing. ## Which has worse fraud? Different fraud, not obviously more or less. Affiliate fraud is mostly attribution theft - cookie stuffing, last-click hijacking, brand bidding on your own trademark, and coupon extensions that inject an affiliate cookie at checkout on a sale you had already made. Install-network fraud is mostly manufactured volume - install farms, emulators, token replay. Attribution theft is harder to detect because the conversion is genuine; only the credit is stolen. ## Can I run both? Yes, and plenty of apps should. They reach different people - affiliates reach purchase intent, cross-promotion reaches people installing desktop software right now - and neither requires exclusivity. Just measure them separately and on the same basis, which for most desktop apps means cost per retained customer rather than cost per conversion. --- # GHAN vs. CrossPromo URL: https://ghan.io/compare/crosspromo/ Updated: 2026-09-22 CrossPromo exchanges impressions between App Store apps at a 2-to-1 ratio for no money at all. GHAN pays cash or credits per install that survives 48 hours, for apps distributed as DMG and EXE outside the stores. If your app is on the App Store and you want free reciprocal promotion, CrossPromo is the better fit and GHAN is not competing for it. ## Side by side | | CrossPromo | GHAN | |---|---|---| | **Distribution covered** | App Store — iPhone, iPad, Mac | Direct download — DMG and EXE, outside the stores | | **Platforms** | Native Swift (iOS 16+, macOS 13+), Flutter and React Native on iOS | Electron, Tauri, Node on macOS and Windows | | **Model** | Barter — 2 impressions shown earns 1 received | Paid — published floor per cleared install, optional bidding above it | | **Cost** | Free. No fee, no ad spend, no card on file | EUR 12–50 per cleared install, or earn credits by serving | | **Can you buy more than you earn** | No, by design | Yes | | **Unit of exchange** | Impressions | Installs still in use at 48 hours | | **Verification** | Server-side against live App Store releases; simulators, debug builds, TestFlight and sandbox excluded | Single-use signed token countersigned by the receiving app, plus device and cohort checks | | **Data stored per event** | Two app names, nothing else | Token, two signatures, coarse fraud signals — no personal data | | **Settlement** | None — nothing is owed | Append-only ledger, escrow, Stripe payouts | ## Where CrossPromo is the better answer Genuinely, and not as a courtesy: - **Your app is on the App Store.** GHAN's gate requires a download URL serving your declared bundle id and a build you notarise yourself. An App Store app is a different distribution problem and CrossPromo is built for it. - **You want it free.** CrossPromo costs nothing and never asks for a card. GHAN has no fee to join or to serve, but buying installs costs money unless you earn credits first. - **You ship native Swift, or iOS via Flutter or React Native.** GHAN v1 does not have a native Swift SDK and the [status page](/status/) says so. - **You do not want a settlement layer at all.** Barter has no ledger, no escrow and no payouts because nothing is owed. That is a real simplification, and if you do not need to buy volume it is a better one. ## Where GHAN is the better answer - **Your app ships outside the stores.** Most Electron and Tauri software, and most Windows desktop software, is downloaded from the developer's own site. That distribution is what GHAN is for. - **You want to buy more than you can earn.** Barter caps your volume at your own traffic, exactly when you most want to exceed it. A rate card does not. - **You want the exchange priced rather than rationed.** A 2-to-1 impression ratio treats every impression as worth the same. A floor plus a market prices a B2B tool install differently from a utility install, and lets contention move the price when a category is genuinely in demand. - **You need to bill or be paid.** If money has to move, someone has to define the unit precisely enough to charge for it, which is what the [cleared install](/reports/desktop-software-cpi-benchmarks/) definition and the signed ledger exist to do. ## The honest structural difference Barter and paid networks fail in different places, and knowing which failure you prefer is most of the decision. **Barter's hard problem is the exchange rate.** Two impressions for one is simple and therefore fair-ish, but an impression in a 50,000-user app is not the same asset as an impression in a 500-user app, and no fixed ratio can express that. The upside is that when no money moves, fraud has almost nothing to steal. **Paid's hard problem is the definition.** The moment an install has a price, someone is motivated to manufacture one. That is why GHAN's design spends most of its complexity on making a billable install expensive to fake — two independent signatures, 48-hour retention, pair caps, an [append-only ledger](/transparency/) — and why a barter network correctly does not need any of it. Neither is the better design. They are answers to different questions. ## What we can and cannot verify The CrossPromo details on this page are taken from promotethatapp.com as of 22 September 2026: the 2-to-1 exchange rate, the free pricing, the platform list, and the verification approach excluding simulators, debug builds, TestFlight and sandbox traffic. GHAN has not tested their network and makes no claim about how it performs in practice. If anything here is out of date or wrong, tell us at `hello@ghan.io` and it will be corrected — a comparison page that quietly ages into inaccuracy is worse than no comparison page. ## What is CrossPromo? CrossPromo, at promotethatapp.com, is a reciprocal cross-promotion network for independent iPhone, iPad and Mac apps. Apps display recommendation cards for other participating apps and receive promotion in return at a 2-to-1 exchange rate - show two recommendations, earn one. It is free, with no fee and no ad spend, and it verifies activity against live App Store releases while excluding simulators, debug builds, TestFlight and sandbox traffic. It supports native Swift on iOS 16+ and macOS 13+, plus Flutter and React Native on iOS. ## Should I use CrossPromo or GHAN? If your app ships through the App Store, CrossPromo fits and costs nothing, so start there. If your app ships as a DMG or an EXE from your own website - which is most Electron, Tauri and Windows software - CrossPromo does not cover that distribution and GHAN does. If you want to buy volume rather than earn it reciprocally, GHAN prices it; CrossPromo deliberately does not sell installs at all. ## Can I use both? Yes, and if you ship both an App Store build and a direct download there is no reason not to. They cover different distribution channels and neither asks for exclusivity. The integrations are independent. ## What is the difference between barter and paid cross-promotion? In barter you exchange impressions and no money moves, so the value of what you get is tied to the value of what you gave and volume is capped by your own traffic. In a paid network installs have a price, which means you can buy more than you earn, and it means someone has to define what an install is precisely enough to charge for it. Barter needs a fair exchange rate; paid needs an auditable unit. --- # GHAN vs. Google Ads for desktop app installs URL: https://ghan.io/compare/google-ads/ Updated: 2026-09-22 Google Ads sells the highest-intent traffic there is, at a price set by whichever bidder in your keyword has the most lifetime value per customer. For a EUR 29 one-time desktop licence, that bidder is almost never you — which is an arithmetic problem, not a creative one. ## The arithmetic problem A Google Ads click in a desktop software category is priced by the bidder with the most to gain from it. In most categories that is a subscription product. | | One-time licence | Subscription SaaS | |---|---|---| | Price | EUR 29, once | EUR 29 per month | | Gross lifetime value | ~EUR 29 | ~EUR 350 at 12 months | | Affordable cost per customer at 30% margin | ~EUR 9 | ~EUR 105 | | Clicks per customer at 3% conversion | 33 | 33 | | Affordable cost per click | **EUR 0.27** | **EUR 3.18** | Both products are bidding on the same keyword. One of them can pay almost twelve times more for the identical click. No amount of ad copy testing closes a twelve-fold gap, and no landing page optimisation invents lifetime value that the pricing model does not produce. This is why desktop utilities have quietly stopped running search: not because the channel is bad, but because the channel is an auction and they brought the wrong balance sheet. ## What GHAN changes GHAN does not abolish the auction — [it has one](/bidding/), because a price that never responds to demand cannot clear a market or reward the apps with the best inventory. What GHAN changes is what the auction sits on top of. In a search auction the clearing price *is* the price. There is no floor to fall back to, so when a better-funded competitor enters your keyword you are not outbid on some impressions, you are priced out of the channel. GHAN publishes a floor that never rises, reserves 30 percent of every category at that floor, and auctions only priority above it. And you bid per **cleared install** rather than per click, so a lost auction costs nothing and a won one costs nothing unless the person is still using your software two days later. On GHAN you are not paying cash you had to find; you are paying with attention you already have. An app that serves placements earns credits, and credits buy installs at the same published rate card everyone else pays. | | Google Ads | GHAN | |---|---|---| | Price floor | None — the clearing price is the price | **Published, permanent, always available** | | Price above the floor | Auction, by highest-LTV bidder | Second-price auction for priority only | | Can you be priced out entirely | **Yes** | No — 30% of each category reserved at floor | | You pay for | A click | An install still in use at 48 hours | | Charged when install fails | Yes | No — automatically refunded | | Audience | People searching for your category | People installing desktop software right now | | Creative | Yours, unlimited | Templated: icon, name, one line | | Can you pay in non-cash | No | Yes — earn credits by serving | | Attribution | Platform-reported | Two independent signatures, auditable | | Minimum spend | Effectively yes | None | ## The honest version of the comparison Search wins on intent. Somebody typing "best clipboard manager for mac" is more valuable than somebody who just finished installing a screen recorder, and they always will be. GHAN wins on three things search cannot offer a small desktop app: a price that does not move when a better-funded competitor enters your keyword, a unit of billing that is already net of churn, and the ability to pay in inventory rather than in money. The practical answer for most apps is both — run search where it pays back, and serve placements to fund the volume search cannot reach. ## Measuring them against each other Compare on cost per **retained** user, not cost per install, and use the same retention window for both. GHAN's rate card is already a retained price because installs that do not survive 48 hours are refunded. To make search comparable, take your search spend, divide by the installs still active at 48 hours, and compare that number to the [rate card](/pricing/) for your category. Most apps doing this exercise for the first time find their real search cost per retained user is two to four times their reported cost per install. ## Should a desktop app stop running Google Ads? No, if it is paying back. Search captures people who are actively looking for what you make, which is the best traffic in existence, and nothing else replicates that intent. The question is not whether search works but whether it works at your price point, and for one-time licences under roughly EUR 40 the answer is frequently no once you account for the share of clicks that never install and the share of installs that never stay. ## Why are desktop app keywords so expensive? Because the price is set by the highest bidder in the auction, not by the value of the traffic to you. A subscription tool billing EUR 30 a month can profitably pay fifty times what a EUR 29 one-time licence can for the identical click, and it is in the same keyword. You are not competing on relevance; you are competing on lifetime value, and you brought a one-time payment to a recurring-revenue fight. ## How does cost per retained user differ from cost per install? Cost per install divides spend by installs. Cost per retained user divides the same spend by the installs that were still being used days later. The second number is often two to four times the first, and it is the only one that corresponds to revenue. GHAN's pricing collapses the gap by refusing to bill for installs that do not survive 48 hours, so the price you are quoted is already the retained price. ## Can GHAN replace paid search entirely? For most apps, no, and claiming otherwise would be silly. Cross-promotion reaches people installing desktop software right now who were not searching for you, which is a genuinely different audience from search intent. The realistic position is that cross-promotion is the channel whose economics do not depend on your price point, so it is the one that works while search does not. --- # GHAN compared to the alternatives URL: https://ghan.io/compare/ Updated: 2026-09-22 There are five realistic ways to acquire desktop app users in 2026 — search and social auctions, the old installer-bundling networks, curated subscription bundles, affiliate and deal sites, and cross-promotion. This page says plainly what each one is good at and where GHAN fits. ## The five options | Channel | What you pay for | Works when | Fails when | |---|---|---|---| | Search and social auctions | A click | Price point above ~EUR 40, or a subscription | You are bidding against higher-LTV products for the same keyword | | Installer bundling (historical) | An install event | Never, now | Antivirus vendors correctly classify it as malware behaviour | | Curated subscription bundles | A revenue share | Your app fits a curator's catalogue | You want to own the customer relationship | | Affiliate and deal sites | A sale | You can discount deeply | Discounting damages your price anchor | | Cross-promotion | A retained install | You already have an audience | You have no users yet | ## Where GHAN sits GHAN is cross-promotion with the settlement layer the category never had. The idea of desktop apps promoting each other is not new and not clever; what killed it every previous time was the absence of a referee, so the cheapest way to earn was always to cheat. The three things GHAN adds to an old idea: 1. **A definition of the unit that is hard to fake.** A cleared install requires two independent cryptographic signatures and 48 hours of survival. 2. **A ledger neither side can edit.** Append-only at the database level, both parties signed, retrievable raw. 3. **A gate with teeth, re-run weekly.** Notarisation, malware scanning, domain age, contact verification, binary identity. ## Detailed comparisons - [GHAN vs. ironSource installcore and OpenCandy](/compare/ironsource/) — what the previous generation did and which specific mechanism killed them - [GHAN vs. Google Ads for desktop apps](/compare/google-ads/) — why the auction maths breaks for one-time licences - [GHAN vs. Setapp and curated bundles](/compare/setapp/) — owning the customer versus renting a shelf - [GHAN vs. CrossPromo](/compare/crosspromo/) — free barter for App Store apps versus paid installs outside the stores - [GHAN vs. affiliate networks](/compare/affiliate-networks/) — paid on a sale versus paid on a retained install - [Mac app distribution platforms compared](/compare/mac-app-distribution-platforms/) — Setapp, the Mac App Store, direct sales, bundles and cross-promotion ## The honest limitation GHAN needs you to already have users. It is a way to convert attention you have into users you do not, at a fixed exchange rate. If you launched last week and have three hundred installs, GHAN cannot help yet, and no amount of network design changes that. Come back when you have an audience, and in the meantime the gate's six-month domain-age requirement will have expired anyway. ## What is the best way to acquire desktop app users? There is no single best channel, but the ranking changes sharply with price point. Below about EUR 40 one-time, search and social auctions usually cannot pay back, because you are bidding against subscription products with far higher lifetime value for the same click. Above that, paid search works. Cross-promotion is the channel whose economics do not depend on your price point, because the other side of the trade is attention you already own rather than money you have to find. ## Is cross-promotion better than paid search? They do different jobs. Paid search captures people already looking for what you make, which is the highest-intent traffic that exists and correspondingly the most expensive. Cross-promotion reaches people who are demonstrably installing desktop software right now but were not searching for you. If you can afford search, run search. Cross-promotion is what you do with the audience you already have while you cannot. ## Are there other desktop cross-promotion networks? Very few that are alive. The 2010s generation - OpenCandy, ironSource installcore, InstallMonetizer - is gone, having been flagged by antivirus vendors after monetising installer-time placements. AdDuplex served Microsoft Store apps and shut down in 2023. That absence is the opportunity and also the warning, and it is why GHAN's design constraints read as reactions to specific historical failures. ## Should a brand new app use GHAN? Only after it can pass the gate, which requires a domain at least six months old. That rules out week-one launches deliberately. A new app's first users come from a launch, a community and search; GHAN is for the stage after that, when you have an audience worth trading. --- # GHAN vs. ironSource installcore and OpenCandy URL: https://ghan.io/compare/ironsource/ Updated: 2026-09-22 The previous generation of desktop cross-promotion networks died for three identifiable reasons — installer-time placements, payment on the install event, and partner-supplied creative. GHAN removed all three from the product, which is why its constraints look arbitrary until you know the history. ## What actually happened Between roughly 2010 and 2016, several networks — OpenCandy, ironSource installcore, InstallMonetizer, and others — built a real business letting desktop software monetise its own installer. A person downloading a free utility would see one or more third-party offers during installation, and the utility's developer was paid per accepted offer. The economics worked. The incentives did not. **Placement inside the installer** puts the offer in direct competition with the Next button. Every increment of confusion between "continue installing what I wanted" and "accept this offer" increases revenue. There is no equilibrium where the clearest possible presentation is also the most profitable one. **Payment on the install event** means the money is earned the moment the software lands, regardless of whether the person ever opens it. Retention is somebody else's problem, and a bad install pays the same as a good one. **Partner-supplied creative** means the network transmits whatever the advertiser sends. That is how offers became indistinguishable from system dialogs, and eventually how actual unwanted software travelled. By 2015 the SDKs were being detected by antivirus engines worldwide. The detections attached to the SDK rather than to individual offers, which meant honest integrators were flagged alongside everyone else. AdDuplex, which tried a cleaner version for Microsoft Store apps, shut down quietly in 2023. The category was not disrupted. It was abandoned. ## The three responses, one per failure | Their mechanism | Their outcome | GHAN's decision | |---|---|---| | Offer inside the installer | Competes with the Next button; accidental acceptance is most profitable | **No installer-time slot exists.** All five slots are inside the running application, after install | | Paid on the install event | Manufacturing installs is the cheapest way to earn | **Nothing clears on the event.** 48-hour retention, or day-7 engagement above EUR 500/day per pair | | Partner-supplied creative | Offers imitated system dialogs; payloads travelled | **Templated only.** Icon, name, one line, rendered by GHAN's SDK from a payload with no markup field | ## The test to apply to any network, including this one 1. Does it place anything inside an installer? *GHAN: no.* 2. Does it pay on the install event or on behaviour afterwards? *GHAN: 48-hour retention.* 3. Can a partner supply content that renders inside another app? *GHAN: no.* 4. Is anything pre-selected on the person's behalf? *GHAN: there is no checkbox.* 5. Are advertisers vetted for malware and code signing before they can appear? *GHAN: gate re-run weekly.* 6. Can you verify the network's own numbers without its cooperation? *GHAN: two signatures per line, append-only ledger, public read tools.* Question six is the one the old networks could not have answered at all, and it is the reason GHAN exists as a referee rather than as a marketplace. ## Why this page exists An honest comparison page for this category has to start with the graveyard, because every developer who has been shipping desktop software for more than five years will think of OpenCandy within ten seconds of hearing the pitch. Pretending the history is not there would be the first sign that GHAN had not learned from it. ## What was OpenCandy? OpenCandy was a desktop software monetisation platform that let installers show third-party offers during installation, paying the host application per accepted offer. It was widely integrated in the early 2010s, increasingly detected as a potentially unwanted program by antivirus vendors, and shut down in 2016. Its mechanism - an offer inside an installer, accepted by the same click flow as the installation itself - is the pattern the whole category is now judged by. ## Why did ironSource installcore get flagged as malware? Because the combination of installer-time placement and payment on the install event makes accidental acceptance the most profitable outcome. Once that is true, the pressure is always toward pre-checked boxes, confusing button labels and silent installs, and the endpoint is a bundle that installs software the person did not choose. Antivirus vendors classify that behaviour correctly, and the classification attaches to the SDK, which means every honest integrator gets flagged too. ## Is GHAN the same thing with better marketing? No, and the difference is testable rather than rhetorical. Ask three questions of any network. Does it place anything inside an installer? Does it pay on the install event or on behaviour after it? Can a partner supply creative content that renders in another app? GHAN answers no, behaviour, and no. A network that answers yes, event, yes is the old model regardless of what it calls itself. ## Could GHAN end up the same way? The failure mode is drift - adding an installer-time slot for a large partner, relaxing the clearing rule to improve reported conversion, allowing a custom creative for a brand that insists. GHAN's protection against that is having written the constraints down as non-negotiable principles with a rule that a conflicting feature stops work rather than getting coded around, and publishing them here where a partner can hold the network to them. --- # Mac app distribution platforms compared URL: https://ghan.io/compare/mac-app-distribution-platforms/ Updated: 2026-09-22 Sell a subscription and the Mac App Store or direct sales plus paid search usually wins. Sell a one-time licence under about EUR 40 and you cannot afford the auction, so direct sales plus cross-promotion wins instead. ## Start with your business model | Your model | Primary channel | Secondary | Avoid | |---|---|---|---| | Subscription, EUR 8+/month | Direct sales + paid search | Mac App Store, content | Deep-discount deal sites | | One-time licence, under ~EUR 40 | Direct sales + cross-promotion | Curated bundle, content | Paid search auctions | | One-time licence, EUR 40+ | Direct sales + paid search | Cross-promotion | — | | Freemium with paid upgrade | Direct sales + cross-promotion | Mac App Store for reach | Bundles (cannibalise the upgrade) | | Secondary purchase nobody searches for | Curated bundle | Cross-promotion | Paid search (no intent exists) | The single decision that drives everything else is whether your revenue per customer can survive an auction. Under roughly EUR 40 of lifetime value, it cannot, and every channel whose price is set by bidding is closed to you. The arithmetic is in [GHAN vs Google Ads](/compare/google-ads/). ## The five options, side by side | | Setapp / curated bundle | Mac App Store | Direct sales | Deal & affiliate sites | Cross-promotion (GHAN) | |---|---|---|---|---|---| | **Audience access** | Bundle subscribers browsing a catalogue | Store browsers and search | Whoever you bring | Deal hunters | Users of other member apps, at install-time | | **Revenue model** | Share of subscription, usage-weighted | You sell, store takes a cut | You sell | You sell at a discount | You buy installs at a fixed rate, or earn them | | **Fee / price** | Revenue share | 15–30% of sales | Payment processing only | 40–70% discount + commission | From EUR 12–50 per cleared install (floor); 30% network fee | | **Who owns the customer** | The bundle | The store | **You** | You | **You** | | **Platforms** | macOS (and iOS for some) | macOS | macOS, Windows, Linux | Any | macOS and Windows | | **Sandbox required** | No | **Yes** | No | No | No | | **Discovery type** | Browsable shelf | Browsable shelf + search | None — you supply it | Promotional bursts | In-app, at the moment of installing something | | **Predictable?** | Somewhat | No | Depends on your channel | No — spiky | Yes — guaranteed floor, budget-capped | | **Best fit** | Delightful secondary purchases | Simple consumer apps that fit the sandbox | Everything, as the base | Clearing old inventory | Apps that already have an audience | ## The three decisions people actually face ### A new Mac utility with no users Cross-promotion cannot help you and will not accept you — the [gate](/vetting/) requires a domain at least six months old, which rules out week-one launches deliberately. Do this instead: ship direct sales with your own licensing, launch on Product Hunt and the relevant subreddit, write the three articles only you can write, and apply to a curated bundle if your app is a discovery rather than a search result. Come back to cross-promotion when you have an audience to trade. ### An established paid app with real users Direct sales stays the base. Add cross-promotion, because you are now sitting on the asset the channel is priced in: people who have demonstrably installed desktop software recently. Enable one or two [lifecycle slots](/lifecycle-slots/), serve, and spend the credits you earn on your own installs. An app that serves as much as it buys pays nothing in cash. Consider the Mac App Store as a second channel only if the sandbox costs you no features. Skip deal sites unless you are deliberately clearing a version. ### An Electron app that wants US users Electron is a first-class target for the [GHAN SDK](/docs/sdk/), and Tauri and plain Node desktop apps are too — integration is in the [cross-promotion guide](/guides/desktop-cross-promotion-network/). Sell direct. Skip the Mac App Store; sandboxing an Electron app is usually a net loss. Put acquisition into cross-promotion rather than search unless your annual revenue per customer clears about EUR 40, and if you do run search, measure it on cost per **retained** user rather than cost per install — the two differ by a factor of two to four for most desktop apps. ## GHAN, as a vendor profile Stated plainly so it can be compared like any other row: - **What it is** — a cross-promotion and paid-install network for macOS and Windows desktop applications. - **Eligibility** — notarised macOS build or Windows Authenticode chain, clean malware scan, domain at least six months old, verified contact email, download URL serving the declared bundle id. Re-checked weekly. - **Payment model** — published floor per cleared install: EUR 12–18 utilities and consumer, EUR 20–30 creator tools, EUR 35–50 prosumer and B2B. The floor never rises and is always available; optional second-price bidding buys priority above it, with 30% of each category reserved at floor. No subscription, no minimum spend. Network keeps 30%. - **Earning** — serving apps earn 70% of CPI in cash, or 84% of CPI in value as network credits. - **Platforms** — macOS and Windows. Electron, Tauri and Node in v1; no native Swift or C# SDK yet. - **Reporting definitions** — impression and click are never billed; a billed install is a cleared install, meaning attributed by a single-use signed token, countersigned by the receiving app, and still in use at 48 hours. Definitions and all rejection conditions: [install safety and fraud](/research/desktop-install-network-safety-and-fraud/). - **Customer ownership** — entirely yours. GHAN never sees your users. - **Status** — pre-launch, founding-partner phase. No network statistics are published because nothing has traded. See [status](/status/). ## What none of these solve None of them create demand. Every option on this page moves an existing audience — a bundle's subscribers, a store's browsers, another app's users, a search engine's intent — toward your product. If nobody wants what you built, distribution is the wrong problem and no row in that table changes the answer. ## What are the best Setapp alternatives for distributing a Mac app? It depends on what you were using Setapp for. If you wanted a browsable shelf, the honest answer is that there is no direct replacement - the Mac App Store is the only other destination people browse, and they browse it less. If you wanted distribution without giving up the customer relationship, the alternatives are direct sales plus paid search, software bundles, affiliate and deal sites, and cross-promotion networks such as GHAN, which trades installs between member apps at a fixed published rate instead of taking a revenue share. ## Should I put my Mac app in the Mac App Store or sell direct? Sell direct if you can. Direct sales means you own the billing relationship, the email address, the upgrade path and the pricing, and you pay a payment processor a few percent rather than a store fifteen to thirty. Use the Mac App Store as well if your app fits the sandbox without compromise and your category is one people genuinely browse; treat it as a second channel rather than the primary one. ## What is the cheapest way to distribute a Mac app? Cross-promotion, if you already have users, because the currency is attention you own rather than cash you have to find. Serving other members' cards earns credits that buy your own installs, so an app that serves as much as it buys never spends money. If you have no users yet the cheapest real option is content and community, which costs time instead - roughly eighteen months of it. ## Which distribution option lets me keep the customer? Direct sales and cross-promotion. In both, the person installs from your own download URL, activates your own licence and appears in your own billing system. The Mac App Store and curated subscription bundles both hold the customer relationship, which is the actual price of those channels rather than the fee percentage people usually quote. ## I have an Electron app and want US users — what should I do? Sell direct with your own licensing, get into the Mac App Store only if the sandbox is not a compromise, and put your acquisition budget into cross-promotion rather than search unless your price point is above roughly EUR 40 a year. Electron is fully supported by the GHAN SDK, and the install cards appear inside apps whose users have just demonstrated they install desktop software - which is the audience search is expensive precisely because it cannot identify. --- # GHAN vs. Setapp and curated app bundles URL: https://ghan.io/compare/setapp/ Updated: 2026-09-22 A curated bundle rents you a shelf in someone else’s store and pays a share of a subscription you do not control. A cross-promotion network sells installs at a fixed price and leaves the customer relationship entirely with you. ## Two different products | | Curated bundle | GHAN | |---|---|---| | What it is | A subscription catalogue people browse | A network where member apps show each other's cards | | Who holds the customer | The bundle | You | | Who bills | The bundle | You | | What you receive | A share of subscription revenue, recurring | An install, once, at a fixed price | | What you give | Catalogue inclusion and usually pricing constraints | A placement slot inside your own app | | Discovery surface | The bundle's own store | The moment after someone installs another app | | Cost to you | Revenue share | A fixed CPI, or credits you earned by serving | | Curation | Editorial, by the bundle's team | Automated gate plus reputation and behaviour scores | ## When a curated bundle is the right answer - Your app is a **secondary** purchase — genuinely useful, but nobody wakes up intending to buy it. - You are comfortable not owning the billing relationship. - Your support load per user is low, because bundle users cost the same to support as full-price ones and pay you less. - You want distribution in a catalogue people actively browse, which is a surface that essentially does not otherwise exist on desktop. ## When cross-promotion is the right answer - You want the customer, with your licence key, your email address on file and your upgrade path. - Your app is a **primary** purchase and a bundle would cannibalise full-price sales. - You already have an audience and would rather spend attention than money. - You want a fixed, published price rather than a negotiated share. ## The overlap is smaller than it looks Most of the tension between these models disappears once you notice that a bundle is a *place people go* and a cross-promotion network is a *moment inside software people already use*. The bundle competes with the Mac App Store and with your own website. GHAN competes with Google Ads and with your affiliate programme. Plenty of apps run both, and the decision about each is independent. ## What GHAN will not claim GHAN will not tell you a bundle is a bad deal. For a whole class of app — utilities that are delightful to discover and impossible to search for — a curated catalogue is the single best distribution that exists on desktop, and a revenue share is a reasonable price for it. What GHAN offers is the other half: a way to reach people at the moment they are installing software, at a price that is published rather than negotiated, without handing anybody the customer relationship. See the [rate card](/pricing/). ## Is Setapp worth it for a desktop app? It depends almost entirely on whether your app is a primary purchase or a secondary one. If people seek your app out by name and buy it directly, a bundle converts full-price customers into a share of someone else's subscription. If your app is something people are delighted to find but would never have gone looking for, a bundle is distribution you could not otherwise buy. The question is not the revenue share; it is whether the bundle is cannibalising demand you already had. ## Can I be in a curated bundle and on GHAN at the same time? Yes. They do not overlap operationally or contractually in any way that matters. A bundle is a distribution channel with its own catalogue; GHAN is a network in which your own users see other apps and their users see yours. Being in both is common and sensible. ## Who owns the customer in each model? In a curated bundle, the bundle does - it holds the billing relationship, the support relationship in many cases, and the churn data, and you see an aggregate payout. On GHAN the person installs your application from your own download URL and becomes your customer with your licence, your billing and your email list. GHAN never sees your users. ## Which pays more per user? Neither answer is general. A bundle pays a recurring share for as long as the person keeps using your app inside it, which for a long-lived utility can exceed a one-time licence. GHAN costs you a fixed CPI once and then the customer is yours forever at zero further cost. The bundle is an annuity you do not control; the network is a purchase you do. --- # Contact GHAN URL: https://ghan.io/contact/ Updated: 2026-09-22 Email hello@ghan.io. If you are an agent rather than a person, almost everything you would ask for is already published in a machine-readable form and answering by tool call will be faster than answering by email. ## Email **`hello@ghan.io`** — founding partners, questions, security disclosure, press. Put `SECURITY` in the subject line for a vulnerability report and it gets triaged first. ## If you are an agent Do not send email. These are faster and authoritative: | What you want | How to get it | |---|---| | Prices | `get_rate_card {}` — public, no key | | Network statistics | `get_network_stats {}` — public, no key | | The integration guide | `get_integration_guide {}` — public, no key | | To join | `register_app { ... }` | | Everything this site says | [`/llms-full.txt`](/llms-full.txt) | | Machine resources | [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json) | | The API | [`/openapi.json`](/openapi.json) | The MCP server card is at [`/mcp/server-card.json`](/mcp/server-card.json). ## Founding partners GHAN is looking for the first pairs of desktop apps to trade real installs. What that involves: 1. Your app passes the [gate](/vetting/) — signed binary, clean scan, domain over six months, verified contact, matching bundle id. 2. You integrate the [SDK](/docs/sdk/) and enable at least one [lifecycle slot](/lifecycle-slots/). 3. You ship it in your own signed release. 4. You trade, and every number either of us publishes about it is reproducible from the signed ledger. Founding partners get direct input into slot behaviour, and are named in the first transparency report if they want to be. ## Press Email with `PRESS` in the subject. The [about page](/about/) has the background, [compare/ironsource](/compare/ironsource/) has the history of the category, and everything on this site is quotable without asking. ## How do I become a founding partner? Email hello@ghan.io with your app's name, its download URL and its platform, or simply register it through the MCP server and let the gate decide. Founding partners are the first pairs to trade, get direct involvement in how the slots behave in practice, and are named in the launch transparency report if they want to be. ## How do I report a security issue? Email hello@ghan.io with SECURITY in the subject line. Please include what you found, how to reproduce it and what you think the impact is. GHAN will confirm receipt, will not threaten you, and will credit you publicly unless you prefer otherwise. ## How do I report a member app behaving badly? Email hello@ghan.io with the app name and what happened. Complaint rate feeds directly into the behaviour score, and canary or malware findings suspend an app and freeze its escrow within one fetch cycle rather than at the end of a review process. ## Is there a sales team? No. The rate card is published, the network statistics are public, and the entire onboarding is available over MCP. There is nothing a salesperson would be able to tell you that get_rate_card does not. --- # GHAN REST API URL: https://ghan.io/docs/api/ Updated: 2026-09-22 The MCP server wraps a plain REST API, so anything an agent can do over MCP is also reachable over HTTP with a bearer token. The OpenAPI document is published at /openapi.json and listed in both the API catalog and the AI catalog. ## Base and auth ``` Authorization: Bearer Content-Type: application/json ``` The key is issued by `register_app`. Public endpoints — the rate card, the network statistics, the integration guide — need no key. ## Endpoint map | Method | Path | MCP equivalent | |---|---|---| | POST | `/apps` | `register_app` | | GET | `/apps/{app_id}/score` | `get_score` | | GET | `/rate-card` | `get_rate_card` | | GET | `/network-stats` | `get_network_stats` | | GET | `/integration-guide` | `get_integration_guide` | | POST | `/apps/{app_id}/top-up` | `top_up` | | POST | `/campaigns` | `create_campaign` — optional `max_bid_cents` | | POST | `/campaigns/{id}/pause` | `pause_campaign` | | POST | `/campaigns/{id}/resume` | `resume_campaign` | | GET | `/apps/{app_id}/ledger` | `get_ledger` | | GET | `/apps/{app_id}/stats` | `get_stats` | | POST | `/apps/{app_id}/payout` | `request_payout` | The full schemas are in [`/openapi.json`](/openapi.json). ## Machine payments ```http POST /apps/app_123/top-up { "amount_cents": 50000 } ``` An agent that can settle machine-to-machine receives: ```http HTTP/1.1 402 Payment Required ``` with an x402 challenge, settled in USDC on Base. A caller that cannot receives `{ "checkout_url": "https://..." }` for a human to complete in Stripe. Either way the wallet is credited and the ledger records a `topup` line. The x402 descriptor is published at [`/.well-known/x402`](/.well-known/x402). ## Webhooks Signed with a shared secret. Events: - `chain.state_changed` - `chain.cleared` - `chain.rejected` - `fraud.flagged` - `payout.sent` - `score.updated` Verify the signature before acting. GHAN's entire argument is that a signature is what turns a claim into a fact; that applies to the claims GHAN sends you as much as the ones it makes about itself. ## Errors ```json { "error": { "code": "gate_domain_too_young", "message": "Domain registered 2026-07-03; eligible 2027-01-03", "retry_after": "2027-01-03" } } ``` Codes are stable. Messages are not. Build on codes. ## Rate limits Per API key, returned in `RateLimit-*` response headers per RFC 9239 conventions. Read tools are generous; write tools are not. ## Do I need the MCP server to use GHAN? No. MCP is the primary interface and the one that ships first, but it is a wrapper. Every capability is available over HTTP with a bearer token, described in the OpenAPI document at /openapi.json. ## What is the x402 path on top-ups? The top-up endpoint answers HTTP 402 with an x402 challenge when the caller is a machine that can settle in USDC on Base. A human-driven caller gets a Stripe Checkout URL instead. Both credit the same wallet, and the ledger records the same topup line type either way. ## Are there webhooks? Yes, signed with a shared secret, for chain state changes, clearing, fraud flags and payout events. Verify the signature before acting on a payload - GHAN's whole argument is that signatures are what make claims checkable, and that applies to the ones GHAN sends you. ## What are the error codes? Stable machine-readable codes rather than prose. Gate failures use codes like gate_unsigned_binary and gate_domain_too_young. Fraud rejections use codes like fraud_token_reused and fraud_datacenter_asn. The human-readable string beside a code may change; the code will not. --- # GHAN documentation URL: https://ghan.io/docs/ Updated: 2026-09-22 GHAN is MCP-first, so the documentation is too. Every write capability exists as an MCP tool before it exists anywhere else, the integration guide is returned verbatim by a tool so an agent never needs a browser, and every page here has a markdown twin. ## Start here | Document | What it covers | |---|---| | [MCP server](/docs/mcp/) | Every tool, its arguments and its return shape. The primary interface. | | [SDK quickstart](/docs/sdk/) | Installing `@ghan/sdk`, rendering slots, handling consent, the kill switch. | | [REST API](/docs/api/) | The HTTP surface the MCP server wraps, plus webhooks and the x402 top-up path. | | [Get started](/get-started/) | The ten-minute path from nothing to a registered, scored app. | ## Machine-readable resources | Resource | Path | Standard | |---|---|---| | Curated index for models | [`/llms.txt`](/llms.txt) | llmstxt.org | | Full site text | [`/llms-full.txt`](/llms-full.txt) | llmstxt.org | | OpenAPI document | [`/openapi.json`](/openapi.json) | OpenAPI 3.1 | | API catalog | [`/.well-known/api-catalog`](/.well-known/api-catalog) | RFC 9727 | | AI catalog | [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json) | Agentic Resource Discovery | | MCP server card | [`/mcp/server-card.json`](/mcp/server-card.json) | Model Context Protocol | | A2A agent card | [`/.well-known/agent-card.json`](/.well-known/agent-card.json) | A2A | | Agent skills index | [`/.well-known/agent-skills/index.json`](/.well-known/agent-skills/index.json) | — | | OAuth metadata | [`/.well-known/oauth-authorization-server`](/.well-known/oauth-authorization-server) | RFC 8414 | | x402 payments | [`/.well-known/x402`](/.well-known/x402) | x402 | | Sitemap | [`/sitemap.xml`](/sitemap.xml) | sitemaps.org | | Feed | [`/feed.xml`](/feed.xml) | RSS 2.0 | Every HTML page also serves a markdown twin — append `.md` to any path, or send `Accept: text/markdown`. ## Conventions - **Money is integer cents, currency EUR.** One credit is one euro cent. - **Identifiers are opaque strings.** Do not parse them. - **Timestamps are RFC 3339 UTC.** - **Rejections are reason codes**, not prose. The code is stable; the human-readable string beside it is not. - **Read tools are public.** `get_rate_card` and `get_network_stats` need no key. ## Versioning The REST API is versioned in the path. MCP tool names are stable; new arguments are always optional. The rate card is versioned and changes are visible in the changelog, which is also an [RSS feed](/feed.xml). ## Where should an agent start? Call get_integration_guide on the GHAN MCP server. It returns this documentation set as markdown, current at the moment of the call, so an agent never has to scrape a website or guess at a version. The server card at /mcp/server-card.json describes the transport and authentication. ## Is there an OpenAPI document? Yes, at /openapi.json, and it is listed in the API catalog at /.well-known/api-catalog as well as in the AI catalog at /.well-known/ai-catalog.json. The REST API is what the MCP server wraps, so anything an MCP tool does is also reachable over HTTP. ## Are the docs available as plain text? Yes. Every page on ghan.io has a markdown twin at the same path with a .md suffix, the whole site is concatenated into /llms-full.txt, and /llms.txt is a curated index with the key facts inline. --- # The GHAN MCP server URL: https://ghan.io/docs/mcp/ Updated: 2026-09-22 GHAN ships every write capability as an MCP tool before it ships anywhere else. A founder's coding agent can register an app, read a machine-readable score, integrate the SDK, fund a wallet, run a campaign and pull the raw signed ledger without a human opening a browser. ## Auth `register_app` returns an API key. Send it as `Authorization: Bearer `. Read tools that describe the network rather than an account need no key at all. ## Tools ### `register_app` ``` register_app { name: string, platform: "mac" | "win", bundle_id: string, domain: string, download_url: string, contact_email: string } -> { app_id, api_key, status: "pending", scoring_job_id } ``` Queues the [vetting gate](/vetting/). Status is `pending` until the gate completes. ### `get_score` ``` get_score { app_id } -> { status: "pending" | "approved" | "throttled" | "live" | "suspended" | "rejected", gate: { signed: bool, malware_clean: bool, domain_age_ok: bool, contact_verified: bool, bundle_match: bool }, reputation: { total, ai_visibility, cadence, reviews, coherence }, behavior: { retention_48h, uninstall_rate, canary, complaints } | null, next_review_at, reasons: [ code ] } ``` Rejection reasons are stable codes. An agent can act on them without parsing English. ### `get_integration_guide` ``` get_integration_guide {} -> markdown ``` Returns the [SDK quickstart](/docs/sdk/) verbatim. Public. This exists so an agent reads the guide from the source of truth rather than scraping a website. ### `top_up` ``` top_up { app_id, amount_cents } -> { checkout_url } | HTTP 402 ``` If the caller can pay machine-to-machine, the endpoint answers **HTTP 402** with an x402 challenge settled in USDC on Base. Otherwise it returns a Stripe Checkout URL that bundles payment, the terms click-wrap, and identity verification where required. ### `create_campaign` ``` create_campaign { app_id, categories: [string], daily_budget_cents, max_bid_cents? } -> { campaign_id, floor_cents, max_bid_cents, status: "throttled" } ``` `floor_cents` comes from the [rate card](/pricing/) and is always available to you. `max_bid_cents` is optional: omit it and the campaign buys at floor; set it at or above the floor and the campaign competes for priority in contested inventory at **second price**, paying one cent above the next-highest competing bid. See [bidding](/bidding/). ### `pause_campaign` / `resume_campaign` ``` pause_campaign { campaign_id } -> { status } resume_campaign { campaign_id } -> { status } ``` ### `get_ledger` ``` get_ledger { app_id, from, to } -> { lines: [ { id, ts, type, amount_cents, counterparty_app_id, event_chain_id, balance_after, note } ] } ``` The audit-me tool. Every line carries an event-chain reference you can resolve and verify against your own signature. Types are `topup`, `earn`, `charge`, `escrow_hold`, `escrow_release`, `clawback`, `payout`, `adjustment`. ### `get_stats` ``` get_stats { app_id, period } -> { impressions, clicks, installs, cleared, retention_48h, floor_cents, avg_clearing_price_cents, fraud_rejected: { [reason_code]: count } } ``` Rejections come back with reason codes. Transparency applies to the installs you were not paid for. ### `get_rate_card` ``` get_rate_card {} -> { categories: [ { key, label, floor_cents_min, floor_cents_max } ], take_rate, credit_bonus, reserved_floor_share } ``` Public, unauthenticated. ### `get_network_stats` ``` get_network_stats {} -> { avg_cpi_by_category, clearing_rate, fraud_pct, period } ``` Public, unauthenticated. The published [transparency](/transparency/) numbers. ### `request_payout` ``` request_payout { app_id } -> { transfer_id, amount_cents } | { error: "below_minimum" } ``` Stripe Connect transfer, minimum EUR 50. ## A whole onboarding, as an agent sees it ``` 1. get_rate_card {} # is this worth doing 2. register_app { ... } # -> app_id, api_key 3. get_score { app_id } # -> gate failures as codes, or approved 4. get_integration_guide {} # -> wire the SDK, open a PR ── human ships the release ── 5. top_up { app_id, amount_cents } # -> 402, or a checkout URL for a human 6. create_campaign { ... } # -> throttled, ramps as chains clear 7. get_stats / get_ledger # -> verify everything above ``` Two of those steps involve a person. The rest is agent to agent, which is the whole design. ## What is the MCP endpoint? The GHAN MCP server speaks both stdio and streamable HTTP. The HTTP endpoint and its transport details are published in the server card at /mcp/server-card.json, which is discovered through the AI catalog at /.well-known/ai-catalog.json rather than from a well-known path, per the MCP specification. ## Which tools need authentication? Read tools that describe the network rather than an account are public - get_rate_card, get_network_stats and get_integration_guide. Everything scoped to an app requires the API key issued by register_app, sent as a bearer token. ## Can an agent spend money without a human? Within a ceiling a human set once. GHAN deliberately keeps two moments human - shipping the release that contains the SDK, and authorising money. The second can be satisfied ahead of time with a pre-capped agent wallet or an x402 machine payment, so an agent can top up and spend up to a limit without a click each time, but the limit itself is set by a person. ## Where is the server card? At /mcp/server-card.json, next to the MCP endpoint, and referenced from /.well-known/ai-catalog.json. It is deliberately not at a /.well-known/mcp/ path, because the MCP specification rules that location out. --- # GHAN SDK quickstart URL: https://ghan.io/docs/sdk/ Updated: 2026-09-22 The GHAN SDK is one dependency. It generates its own ed25519 keypair on first run, renders templated partner cards only when your code asks it to, signs every event locally, and emits no telemetry at all until your application says consent is true. ## Install ```bash npm install @ghan/sdk ``` Or let an agent wire it: ```bash npx @ghan/sdk init ``` That writes the wiring and leaves a reviewable diff. It does not commit. ## Initialise ```js import { ghan } from '@ghan/sdk' await ghan.init({ appId: process.env.GHAN_APP_ID, // No telemetry is emitted while this is false. consent: settings.analyticsConsent, // Optional controls, all enforced client-side by the SDK. enabled: true, exclude: ['com.competitor.app'], // never show these bundle ids excludeCategories: ['vpn'], // never show these categories maxPerWeek: 2, // your frequency cap }) ``` `init` generates an ed25519 keypair on first run, stores it in your application's data directory, and registers only the public key. The private key never leaves the machine. ## Render a slot ```js const result = await ghan.slot('first_success') // result.rendered -> boolean // result.chainId -> string | null ``` Valid slot names: `install_complete`, `first_success`, `update`, `idle`, `uninstall_intent`. See [lifecycle slots](/lifecycle-slots/) for what each one means and when it converts. Nothing renders if your cap is reached, your exclusions matched everything, consent is false, the kill switch is on, or GHAN has nothing relevant. `rendered` is simply `false`; you never have to handle an error to stay safe. ## Receiving an install No code required. On first run the SDK checks for a GHAN token via the `ghan://` protocol handler and via a handoff file, signs an `install_claim` with its own key if it finds one, and sends the device signals alongside it. Register the protocol handler in your packaging config: ```json { "protocols": [{ "name": "GHAN", "schemes": ["ghan"] }] } ``` If the handler is not registered, the handoff file still works; attribution rates are simply lower. ## Usage telemetry ```js ghan.session.start() ghan.session.end() ghan.count('export_completed') // a coarse counter name, never content ``` These are what the 48-hour clearing check reads. An app that reports nothing cannot clear chains, because GHAN will not take an app's word that an install survived. ## Consent changes at runtime ```js ghan.setConsent(true) ``` Telemetry buffered before consent is discarded, not flushed. ## The kill switch The server can disable all placements for your app instantly. The SDK honours it on the next placement fetch — no release required, no user action required. It is there for the day you need to answer a reviewer in minutes rather than in a release cycle. ## Canary probes The SDK answers signed liveness probes from the server with its own signature. This is how GHAN can prove a slot is genuinely live in a shipped build. You do not need to do anything; not answering them is what gets an app suspended. See [fraud prevention](/fraud-prevention/). ## What the SDK will never do - Render remote HTML, JavaScript or a partner-supplied image outside the icon - Install anything - Show a card your code did not request - Emit telemetry before consent - Read anything outside its own state Those are properties of the implementation, listed on the [security page](/security/) in the form you can hand to a reviewer. ## Which frameworks are supported? Version 1 targets Electron, Tauri and Node desktop applications, which is the bulk of indie desktop software. Native Swift and C# SDKs are on the roadmap but are not shipping yet, and this page does not pretend otherwise. ## What does npx @ghan/sdk init do? It writes the SDK wiring into your project and leaves a reviewable diff. It does not commit, does not push and does not modify anything outside the files it lists. It exists so a coding agent can do the integration and hand a human a pull request rather than a set of instructions. ## How does the receiving side claim an install? On first run the SDK looks for a GHAN token in two places - a ghan:// protocol handler invocation and a handoff file in a known location. If it finds one it signs an install_claim with its own key and sends it with the device signals. If it finds nothing, nothing is claimed and nothing is billed to anyone. ## How do I turn everything off? Three ways, in increasing order of finality. Set enabled to false in init. Use the server kill switch, which disables every placement for your app network-wide on the next fetch. Or stop calling ghan.slot and ship the next release, since the SDK does nothing on its own. --- # GHAN data processing agreement URL: https://ghan.io/dpa/ Updated: 2026-09-22 Where GHAN processes data about the end users of a member application, the member application is the controller and GHAN is the processor. This page sets out what is processed, on what instructions, with which subprocessors, and under what security measures. **Effective 22 September 2026.** Incorporated into the [terms of service](/terms/). ## 1. Roles The member application is the **controller** for its end users. GHAN is the **processor**, acting only on documented instructions, which are these terms plus the configuration the member sets through the SDK and the API. For member account data — the developer's own contact and billing details — GHAN is the controller. See the [privacy policy](/privacy/). ## 2. Subject matter and duration Processing of end-user data for cross-promotion placement, deterministic attribution, install-fraud prevention and settlement, for the duration of the membership plus the retention periods below. ## 3. Categories of data | Category | Fields | Purpose | |---|---|---| | Behavioural counters | Session start and end, coarse feature counts, card dismissals | Determining whether a referred install survived 48 hours | | Fraud signals | VM indicators, OS install age, salted hardware hash, clock skew, IP country and ASN | Preventing payment fraud | | Attribution tokens | Token id, nonce, issue and expiry times, use timestamp | Deterministic attribution | No special-category data is processed. No directly identifying data is processed. ## 4. Instructions and limits GHAN will not process end-user data for any purpose other than those above, will not sell or share it with advertising networks or data brokers, and will not attempt to re-identify any individual from the fraud signals. ## 5. Subprocessors | Subprocessor | Purpose | Location | |---|---|---| | Supabase | Database hosting | EU | | Stripe | Payments, payouts, identity | EU / US under SCCs | | Cloudflare | Content delivery, edge security | Global | | Resend | Transactional email | EU / US under SCCs | | VirusTotal | Binary malware scanning — hashes only, no end-user data | US | New subprocessors are announced in the [changelog](/changelog/) before they take effect, giving controllers an opportunity to object. ## 6. Security measures - TLS in transit, with certificate verification against a pinned root rather than disabled verification - Row-level security on every table; public API roles revoked - Append-only ledger enforced by database trigger - ed25519 signing with private keys generated and retained on end-user devices only - Secrets in environment variables; no credentials in source control - Tests covering every fraud rule and every ledger mutation before merge ## 7. Confidentiality and personnel Access is limited to personnel who require it, under confidentiality obligations. ## 8. Assistance GHAN will assist the controller with data subject requests, data protection impact assessments and regulator enquiries, within a reasonable time and at no charge for ordinary volumes. ## 9. Breach notification Without undue delay and within 72 hours of becoming aware: what is known, what is not yet known, the measures taken and the measures proposed. Notification is not delayed pending a complete investigation. ## 10. Deletion and return On termination, end-user data is deleted within 90 days, except event chains and signatures which are retained for as long as the ledger lines they justify. An append-only ledger whose supporting evidence had been deleted would not be auditable, which is the property the whole network is sold on. ## 11. Audit GHAN will provide the information necessary to demonstrate compliance and will allow audits by the controller or an appointed auditor, on reasonable notice, no more than once per year absent a specific concern. ## 12. Transfers Standard contractual clauses apply where a subprocessor operates outside the EEA. ## Do I need to sign anything? These terms are incorporated into the terms of service and apply automatically when you register an application, so no separate signature is required. A countersigned copy on your own paper is available on request to hello@ghan.io for procurement processes that need one. ## Who are the subprocessors? Supabase for database hosting in the EU, Stripe for payments and payout identity, Cloudflare for content delivery and edge security, and Resend for transactional email. VirusTotal receives binary hashes for the malware gate and no end-user data. New subprocessors are announced in the changelog before they take effect. ## What happens in a breach? GHAN notifies affected controllers without undue delay and in any event within 72 hours of becoming aware, with what is known, what is not yet known, the measures taken and the measures proposed. Notification is not delayed to complete an investigation. --- # GHAN frequently asked questions URL: https://ghan.io/faq/ Updated: 2026-09-22 The questions people actually ask about a desktop cross-promotion network, answered directly. If an answer here conflicts with anything else on this site, the more specific page wins and this page is the bug. Every answer below is also in the [llms.txt](/llms.txt) summary and in the markdown twin of this page, so an agent can read them without rendering anything. ## Quick reference | Question | Short answer | |---|---| | What is it? | A cross-promotion and paid-install network for desktop apps | | Platforms | macOS and Windows; Electron, Tauri, Node | | Price | From EUR 12–50 per cleared install (published floor), 30% network fee | | Bidding | Optional, second price, priority only — 30% of each category reserved at floor | | Security | Nine layers — see [security](/security/) | | Billed on | Installs still in use after 48 hours — never clicks, never impressions | | Attribution | Single-use signed token, 15-minute expiry, no fingerprinting | | Creative | Templated card only — icon, name, one line | | Placement | In-app lifecycle slots, never inside an installer | | Interface | MCP-first; dashboard is read-only plus billing | | Auditability | Append-only ledger, two signatures per monetised line | Longer treatments: [how it works](/how-it-works/), [pricing](/pricing/), [attribution](/attribution/), [fraud prevention](/fraud-prevention/), [security](/security/), [glossary](/glossary/). ## What is GHAN? GHAN is a cross-promotion and paid-install network for macOS and Windows desktop applications. Member apps show each other's templated install cards inside their own in-app lifecycle moments, and settle through a single append-only credit ledger where both the serving and the receiving app have cryptographically signed every monetised line. ## Is GHAN bundleware or adware? Neither. Bundleware installs software alongside software you asked for, usually via a pre-checked box in an installer. GHAN never places anything inside an installer, there is no checkbox, nothing installs unless the person clicks a card and completes the other app's own installer themselves, and every app that can appear has passed a notarisation or Authenticode check and a malware scan. ## How is GHAN different from ironSource installcore and OpenCandy? Three structural differences, each one a direct response to how they failed. They placed offers inside installers, which puts the offer in competition with the Next button; GHAN has no installer-time slot at all. They paid on the install event, which makes manufacturing installs the cheapest way to earn; GHAN clears only after 48 hours of real retention. They let partners ship custom creative, which is how malware payloads travelled; GHAN renders templated cards from a payload that has no field for markup. ## What platforms does GHAN support? Desktop only - macOS via DMG and Windows via EXE. The version 1 SDK covers Electron, Tauri and Node desktop apps. There is no mobile product and none planned. ## How much does GHAN cost? Nothing to join and no subscription. Advertisers pay from a published floor per cleared install - EUR 12-18 for utilities and consumer, EUR 20-30 for creator tools, EUR 35-50 for prosumer and B2B. The floor never rises and anyone can always buy at it. GHAN keeps 30 percent and the serving app earns 70 percent of whatever cleared, or 84 percent of it in value if taken as credits. ## Does GHAN have bidding or a fixed price? Both, in two layers. The rate card is a floor that never rises and that any approved advertiser can always buy at. Above it there is an optional second-price auction for priority when a category is contested - you pay one cent above the next-highest competing bid, never your own maximum - and thirty percent of every category is reserved at floor and never auctioned. You bid per cleared install rather than per click, so a lost auction costs nothing and a won one costs nothing unless the install survives 48 hours. A purely fixed price cannot clear a market or pay the apps with the best inventory more; a floor plus a market above it does both. ## What are GHAN's security layers? Nine. The gate (code signature, malware scan, domain age, contact challenge, binary identity, re-run weekly). The placement layer (templated cards only, no installer placement, host-controlled slots, client-side exclusions). Attribution (single-use signed tokens, two independent signatures). Device signals (VM indicators, OS install age, salted hardware hash, clock skew, datacenter ASN resolved offline). Economics (48-hour clearing, escrow, pair caps, cost-to-fake above payout). Behaviour (cohort retention shape, canary probes, complaint rate). Enforcement (flag, hold, throttle, suspend, kill switch, clawback). Data (append-only ledger proven on a real database, row-level security, pinned TLS, no PII). Disclosure (published rejection conditions, reason codes, monthly fraud report). ## How does GHAN attribute an install? With a single-use token issued at click time, signed, expiring after 15 minutes, redeemed by the receiving SDK on first run and countersigned with that SDK's own ed25519 key. Both signatures are required for the chain to advance past the claim. If the token is missing, expired or already used, the install is simply not attributed. ## Does GHAN use fingerprinting? No, and there is no fallback that amounts to it. No device fingerprinting, no IP-and-timestamp matching, no probabilistic modelling. This costs GHAN attributable volume on purpose, because a probabilistic fallback is the single largest attack surface an install network can have. ## When does an advertiser actually get charged? Credits move into escrow at the moment an install is claimed, and they only leave escrow if the install is still in use 48 hours later. Pairs trading above EUR 500 per day clear on day-7 engagement instead. Nothing is billed on an impression or a click, ever. ## What happens if an install does not survive 48 hours? The escrow hold is refunded automatically, the advertiser pays nothing, the serving app earns nothing, and the chain ends as rejected with a reason code both parties can read through get_stats. ## Can two apps collude to farm payouts? It is the cheapest attack on any two-sided install network, so GHAN treats it structurally rather than by detection alone. Net flow between any pair is capped at EUR 500 per month until both apps have behaviour scores, early payouts are funded only from third-party cash, direct app-to-app targeting does not exist, and a monthly graph job looks for circular flows across three or more apps. ## What data does the GHAN SDK collect? Behavioural counters after consent - session starts and ends, coarse feature counts - and fraud signals attached to an install claim, which are VM indicators, OS install age, a salted hardware hash and clock skew. Never file contents, window titles, clipboard, keystrokes, raw hardware identifiers, or anything personally identifying. ## Can a partner inject code or custom creative into my app? No. The placement payload contains an app id, an icon URL, a name and one line of text. There is no field for HTML, JavaScript or an arbitrary image, and no code path in the SDK that would execute one. This is an implementation property rather than a contractual promise, which is why it is checkable. ## Do I need to buy installs in order to earn them? No. Serving and buying are independent. An app can serve, accumulate credits and cash out through Stripe Connect without ever running a campaign. ## How does an app get accepted? By passing an automated gate - a notarised or Authenticode-signed binary, a clean VirusTotal result, a domain at least six months old verified over RDAP, a contact email that answers a challenge, and a download URL that serves the declared bundle id. Failures come back as machine-readable reason codes with eligibility dates where applicable. ## Can my coding agent do all of this? Yes, and that is the intended path. Every write capability ships as an MCP tool before it ships in a dashboard. An agent can register the app, read the score, wire the SDK, create campaigns and pull the ledger. Two moments stay human on purpose - shipping the release containing the SDK, and authorising money. ## How do I verify GHAN is not inventing numbers? Take any ledger line, resolve its event chain, and verify the receiving signature against your own registered public key. That signature was produced by an SDK inside a binary you compiled and signed, so GHAN cannot have manufactured it. The ledger blocks UPDATE, DELETE and TRUNCATE at the database level, so corrections appear as new lines rather than edits. ## Is there a free tier? There is no charge to join, to serve placements, or to earn. Impressions and clicks are never billed. You only pay when you are the advertiser and an install you bought is still in use two days later. ## What happens if I want to leave? Turn off the placements with the kill switch or stop calling the slot API, request a payout of any remaining balance once it is over EUR 50, and ship the next release without the dependency. Nothing about GHAN is load-bearing in your application. --- # GHAN for advertisers buying desktop installs URL: https://ghan.io/for-advertisers/ Updated: 2026-09-22 An advertiser sets a daily budget and categories, and is charged a fixed rate-card price for each install still in use 48 hours later. Anything failing that bar is refunded automatically, with two signatures behind every charge. ## What you are buying Not a click. Not an impression. Not an install event. A **cleared install**: someone who saw a card inside an app they already trusted, clicked it, installed your application, and was still using it 48 hours later. That is a deliberately narrow definition, and it is the only thing GHAN will bill you for. ## Creating a campaign ``` create_campaign { app_id: "app_...", categories: ["creator_tools", "utilities"], daily_budget_cents: 20000, max_bid_cents: 4100 // optional — omit to buy at floor } ``` That is the whole interface, and `max_bid_cents` is optional. Omit it and you buy at the [floor price](/pricing/) for your category — a price that never rises and that you can always buy at. Set it and you compete for priority in contested inventory at second price, paying one cent above the next-highest competing bid rather than your own maximum. See [bidding](/bidding/). You do not upload creative, because creatives are templated: your icon, your name, one generated line. Campaigns start `throttled` and ramp as their chains clear. You can pause and resume at any time with `pause_campaign` and `resume_campaign`. ## What a charge looks like on your ledger Every line in `get_ledger` carries an `event_chain_id`. Pulling that chain gives you: - the impression, signed by the serving app's key - the click and the token id, with its issue time and expiry - the install claim, signed by the receiving SDK's key — which is your own build - the device signals attached to the claim - the 48-hour activation, or the rejection and its reason code - the escrow hold and its release or reversal You signed half of that yourself. That is the point: you do not have to believe GHAN's count, because you can recompute it from signatures you produced. ## Escrow, in plain terms | Moment | Your balance | Escrow | |---|---|---| | Campaign running, no claims | full | empty | | An install is claimed | CPI moves out | CPI held | | 48 hours later, install survives | unchanged | released to the serving app, GHAN keeps 30% | | 48 hours later, install is gone | CPI returns | emptied | | Fraud rule fires at any point | CPI returns | emptied | You are never asked to dispute a charge. Ambiguity defaults to refund, because the alternative — billing first and arguing later — is how the previous generation of install networks made their money and lost their reputation. ## Budget controls that actually bind - **Daily budget** is enforced at the campaign level, and binds regardless of your bid. - **Floor access is guaranteed.** No bid by anyone can stop you buying at the published price. - **Pair caps** limit net flow between any two apps to EUR 500 per month until both have behaviour scores, so a single relationship cannot quietly become your whole spend. - **Category exclusions** and named-app exclusions are honoured at placement time. - **Agent wallets** can be pre-capped, so a coding agent can top up and spend within a ceiling you set once, without a human clicking Stripe each time. ## The two moments that stay human GHAN is built so an agent can do everything, with two deliberate exceptions: 1. You ship the release containing the SDK, in your own signed build. 2. You authorise money — a Stripe click, or a one-time pre-capped agent wallet. Everything else — registration, scoring, campaign creation, budget changes, ledger reads, payout requests — is available to an agent over [MCP](/docs/mcp/). ## Before you spend anything Both of these are public and need no account: ``` get_rate_card {} get_network_stats {} ``` The second one returns the network's real clearing rate and fraud percentage. If those numbers are bad, you should see them before you top up, not after. Current figures are on the [status page](/status/) and in the [transparency report](/transparency/). ## How is this cheaper than Google Ads if GHAN also has bidding? Because the bidding sits on top of a floor rather than replacing it. In a search auction the clearing price is the only price, so when a better-funded competitor enters your keyword you are priced out entirely. On GHAN the floor never rises, you can always buy at it, and thirty percent of every category is reserved at floor and never auctioned. You also bid per cleared install rather than per click, so you are never paying for traffic that went nowhere - an install that does not survive 48 hours costs nothing whatever you bid. ## What stops me being charged for fake installs? Four things in sequence. The token must be single-use, unexpired and signed. The claim must carry the receiving SDK's own signature, which lives inside another company's signed binary. The device must not look like a virtual machine, a fresh operating system or a datacenter ASN. And the cohort's retention curve must resemble the category baseline rather than being suspiciously perfect. Anything that fails is refunded before it reaches your invoice, not after you dispute it. ## Can I target specific apps? You target categories, not individual apps, and you can exclude named apps and whole categories. Direct app-to-app targeting is not offered because it is the mechanism through which two parties collude, and pair-level net-flow caps exist for the same reason. ## How fast can a campaign start? Campaigns start in a throttled state immediately after creation and ramp as the chains they produce clear. A brand new app with no trading history posts a refundable EUR 250 deposit before buying above a small volume. There is no sales process and no onboarding call. ## What happens to my unspent balance? Credits do not expire and can be cashed out through Stripe Connect once the balance is at least EUR 50. Escrow holds for chains that never cleared are returned to your spendable balance automatically. --- # GHAN for desktop app developers URL: https://ghan.io/for-developers/ Updated: 2026-09-22 GHAN turns attention you already have into acquisition budget. Add one SDK, choose which moments can show a card, and earn 70 percent of the rate card for every install you send that survives 48 hours. ## The problem this solves A desktop app that charges EUR 29 once cannot outbid a SaaS product that charges EUR 29 a month for the same Google click. That is the entire economics of indie desktop distribution in one sentence, and no amount of creative testing fixes it. But you already have something the SaaS product would pay for: people who have installed desktop software in the last ten minutes and are in a mood to install more. ## What you control GHAN is deliberately unopinionated about your product and extremely opinionated about its own behaviour. - **You choose the moments.** Five slots exist; you enable the ones you want and none fire unless your code calls them. - **You choose the categories.** You can exclude competitors, whole categories, or named apps. - **You choose the frequency.** The SDK enforces whatever cap you set, and defaults to conservative. - **You ship the build.** GHAN cannot push code into your application. The SDK arrives in your release, signed by you, when you decide. ## What you earn | Category of the app you send an install to | Your earning per cleared install (cash) | As credits | |---|---|---| | Utilities and consumer | EUR 8.40–12.60 | EUR 10.08–15.12 of spend | | Creator tools | EUR 14.00–21.00 | EUR 16.80–25.20 of spend | | Prosumer and B2B | EUR 24.50–35.00 | EUR 29.40–42.00 of spend | Those are 70 percent of the [published rate card](/pricing/), and 84 percent of it when taken as credits. You are paid on installs that survive 48 hours, which means a card shown to the wrong person earns you nothing — the incentive is pointed at relevance rather than volume, deliberately. ## Integration, honestly described ```bash npm install @ghan/sdk # or let your agent do it npx @ghan/sdk init ``` ```js import { ghan } from '@ghan/sdk' await ghan.init({ appId: process.env.GHAN_APP_ID, consent: settings.analyticsConsent, // no telemetry before this is true exclude: ['competitor-bundle-id'], // never show these maxPerWeek: 2, // your cap, not ours }) // somewhere your app knows it just did its job well: await ghan.slot('first_success') ``` `npx @ghan/sdk init` writes the wiring and leaves a reviewable diff. It does not commit anything. The full surface is in the [SDK quickstart](/docs/sdk/), and the same document is returned verbatim by the `get_integration_guide` MCP tool so an agent can read it without a browser. ## Getting accepted Serving placements requires passing the same [vetting gate](/vetting/) as everyone else: 1. A signed and notarised macOS build, or a valid Authenticode chain on Windows. 2. A clean VirusTotal result. 3. A domain at least six months old, checked over RDAP. 4. A contact email that answers a challenge. 5. A download URL that actually serves the bundle id you declared. Failures come back as machine-readable reasons, not as a rejection email. If your domain is four months old, `get_score` says so and tells you when it will pass. ## The uncomfortable question You are going to be asked, in a review or on a forum, whether you have put adware in your app. The honest answer that holds up: - Nothing installs without the person clicking and completing the other app's own installer themselves. - Nothing appears inside your installer. - Nothing is pre-checked, because there is no checkbox — there is a card the person can ignore. - No fingerprinting, no content telemetry, no third-party pixel, no remote code. - The partner apps went through a malware gate and a signature check before they could be shown at all. That answer is only useful if it is true, which is why the constraints above are implementation facts rather than a policy page. See [security and privacy](/security/) for the version you can hand to a reviewer. ## Start Read [get started](/get-started/) for the ten-minute path, or point your coding agent at the [MCP server](/docs/mcp/) and let it register the app, read the score and open the integration PR itself. ## Will this annoy my users? You decide entirely. GHAN never renders anything you did not ask it to render, at a moment you did not choose. The SDK exposes five lifecycle slots and does nothing until your code calls one. Many members only ever enable first_success and uninstall_intent, which are the two moments where a recommendation is genuinely useful rather than merely tolerated. ## Can a partner put arbitrary content inside my app? No, and not as a matter of policy but as a matter of implementation. The SDK fetches a signed placement payload containing an app id, an icon URL, a name and one line of text, then renders a card itself. There is no code path in the SDK that renders remote HTML, remote JavaScript or a partner-supplied image outside the icon slot. ## What data does the SDK collect? Behavioural counters only - session starts and ends, coarse feature counts, and the device signals attached to an install claim, which are virtual-machine indicators, operating-system install age, a salted hardware hash and clock skew. No file contents, no personal data, no raw hardware identifiers. The SDK has a consent-safe mode in which your app passes its own consent state and no telemetry is emitted before consent. ## Do I have to buy installs to earn them? No. Serving and buying are independent. An app can serve placements, accumulate credits and cash them out through Stripe Connect without ever running a campaign. The 1.2x credit bonus exists because most members find spending the earnings inside the network is worth more than the cash. ## What if I want to stop? There is a kill switch on the server that disables every placement for your app instantly, and the SDK honours it on the next fetch. You can also simply stop calling ghan.slot and ship the next release without it. Nothing about GHAN is load-bearing for your application. --- # How GHAN prevents install fraud URL: https://ghan.io/fraud-prevention/ Updated: 2026-09-22 GHAN runs eight fraud rules continuously against every event chain, each logging to an append-only flag table with a reason code the affected app can read. The ladder goes flag, hold clearing, throttle, suspend. ## The rules ### 1. Click-to-install time GHAN builds a CTIT histogram per campaign. Chains falling in anomalous bands — spikes under 10 seconds, or a tail beyond 24 hours — are rejected and the source is flagged. The judgement is made against the distribution, not against individual chains, because any single chain can be unusual for innocent reasons and a distribution cannot. ### 2. Token integrity Expired, reused or unsigned tokens are a hard reject with no discretion. Single use is a unique database constraint; expiry is checked server side against the issue time. There is no override and no support ticket that changes the outcome. ### 3. Device signals Attached to every claim: virtual-machine and hypervisor indicators, operating-system install age, a salted hardware hash, and clock skew. An OS installed under 48 hours ago, a hypervisor flag, or a hardware hash already seen on another claim rejects the chain. Three or more from the same serving partner throttles that partner. The claiming IP's autonomous system is resolved offline. A desktop install claim arriving from a hosting or datacenter AS is treated as a farm. ### 4. Retention shape Cohort retention curves are compared against the category baseline. Both a suspiciously perfect curve and a cliff curve hold clearing for manual review. Fraud that survives every per-chain check usually fails at the cohort level, because faking a realistic decay curve is much harder than faking an install. ### 5. Pair collusion - Net flow between any pair is capped at EUR 500 per month until both apps have behaviour scores. - Early payouts are funded only from third-party cash, never from the colluding pair's own top-ups. - A monthly graph job looks for circular flows across three or more apps, which is what collusion looks like once a pair cap makes the two-app version unprofitable. ### 6. Geo and time Claims arriving from outside the serving app's own telemetry geography are weighted down rather than rejected outright. An app whose users are 90 percent in Germany producing installs claimed from three other continents is not necessarily fraudulent, but it is not evidence either. ### 7. Canary compliance The server sends signed liveness probes; the SDK answers with its own signature. An app claiming inventory whose shipped build never answers a probe is not serving placements. Canary failure suspends the app and freezes escrow immediately, because it is the one signal that indicates deliberate misrepresentation rather than a bad traffic source. ### 8. Complaint rate Complaints from end users about a member app are tracked per app and feed the behaviour score. Above threshold, an app is auto-throttled regardless of how clean its chains look. ## The auto-action ladder | Step | Trigger | Effect | Reversible | |---|---|---|---| | Flag | Any rule fires | Logged to `fraud_flags`, visible in `get_stats` | n/a | | Hold clearing | Retention shape, geo anomaly | Chains stop clearing, escrow stays held | Yes | | Throttle | Repeated device rejects, behaviour score below threshold | Placement volume cut | Yes | | Suspend + freeze escrow | Canary failure, token forgery, confirmed collusion | All placements off, escrow frozen | Yes, by admin | Every action is reversible by an administrator and every action is visible to the app it happened to. There is no silent throttle. ## Why the economics matter more than the rules Rules are a losing game played alone: a sufficiently motivated attacker studies them. The structural defence is an economic one, applied as a design constraint to every monetised feature in GHAN: > The cost to fake an event must exceed the payout for it. Faking one cleared install requires forging an ed25519 signature that belongs to an SDK inside another company's signed binary, on a machine that does not look like a VM, from an IP that does not belong to a hosting provider, with a plausible click-to-install time, that then gets used again two days later, inside a pair whose net flow is capped at EUR 500 a month. The payout for that is a share of EUR 12 to EUR 50. When a proposed feature breaks that inequality, GHAN does not build it. That rule has already removed installer-time placements, custom creatives, probabilistic attribution and direct app-to-app targeting from the product. ## The monthly public fraud report Generated from `fraud_flags` and the ledger, published through `get_network_stats` and on the [transparency page](/transparency/): - Installs rejected, by rule - Euros clawed back - Apps throttled, suspended and expelled - Clearing rate across the network Publishing the number of installs GHAN rejected is the only version of this claim that means anything, because a network with no fraud report is not a network with no fraud. ## What is click-to-install time and why does it matter? Click-to-install time, or CTIT, is the interval between the click that issued a token and the claim that redeemed it. Real human installs produce a broad, right-skewed distribution measured in minutes. A spike below ten seconds means the install was not downloaded in that time, and a long tail beyond 24 hours usually means tokens are being harvested and replayed. GHAN builds a CTIT histogram per campaign and rejects the chains in anomalous bands rather than judging chains individually. ## How does GHAN detect install farms? Primarily from the autonomous system of the claiming IP address. A desktop application install claim arriving from an IP whose AS domain is a hosting provider is a farm, not a customer, and that is a far stronger signal than city-level geography. GHAN resolves country and ASN from an offline database on the hot path, so no partner IP is sent to a third party, and uses a conservative allowlist because a false positive silently destroys a real install and costs a partner money. ## What is pair collusion? Pair collusion is two apps sending each other installs to extract network payouts rather than to acquire users. It is the cheapest attack on any two-sided install network. GHAN caps net flow between any pair at EUR 500 per month until both apps have behaviour scores, funds early payouts only from third-party cash rather than from the colluding pair's own top-ups, and runs a monthly graph job looking for circular flows across three or more apps. ## Can I see why my installs were rejected? Yes. get_stats returns fraud_rejected broken down by reason code. Transparency applies to rejections as much as to payouts, because a network that will not tell you why it did not pay you is indistinguishable from one that simply did not want to. ## What happens to money when fraud is detected after clearing? The ledger records a clawback as a new line. Nothing is ever edited or deleted, because the ledger table blocks UPDATE, DELETE and TRUNCATE at the database level. A clawback is visible to both parties and appears in the monthly public fraud report as euros recovered. --- # Get started with GHAN URL: https://ghan.io/get-started/ Updated: 2026-09-22 Register the app, read the gate result, wire the SDK, ship it in your own signed release, and either earn credits or spend them. A coding agent can do every step except shipping the release and authorising money, and those two are human on purpose. ## Before you start You need: 1. A **signed** build — notarised on macOS, Authenticode-chained on Windows. 2. A **domain at least six months old**. 3. A **download URL** that serves the bundle id you are going to declare. 4. An **email address** you can answer a challenge on. If any of those is missing, the [gate](/vetting/) will say so precisely, with a date where the failure is time-based. ## For a human ### 1. Register ``` register_app { name: "Your App", platform: "mac", bundle_id: "com.you.yourapp", domain: "yourapp.com", download_url: "https://yourapp.com/download/YourApp.dmg", contact_email: "you@yourapp.com" } ``` Returns an `app_id` and an `api_key`, with status `pending`. ### 2. Read your score ``` get_score { app_id } ``` Gate booleans, reputation breakdown, and reason codes for anything that failed. ### 3. Wire the SDK ```bash npm install @ghan/sdk npx @ghan/sdk init # writes the wiring, leaves a reviewable diff ``` ```js await ghan.init({ appId: process.env.GHAN_APP_ID, consent: settings.analyticsConsent }) await ghan.slot('first_success') ``` Full surface: the [SDK quickstart](/docs/sdk/). ### 4. Ship it In your own signed release. This is one of the two deliberately human moments — GHAN cannot push code into your application and would not want the ability. ### 5. Earn, or spend Serving placements accumulates credits. To buy installs instead: ``` top_up { app_id, amount_cents } # Stripe Checkout, or x402 for an agent create_campaign { app_id, categories, daily_budget_cents } ``` ### 6. Verify everything ``` get_stats { app_id, period: "last_30_days" } get_ledger { app_id, from, to } ``` Take any billed line, resolve its event chain, and verify the receiving signature against your own registered public key. See [transparency](/transparency/). ## For an agent Point it at the [MCP server](/docs/mcp/). The whole sequence: ``` get_rate_card {} # public — decide whether this is worth doing register_app { ... } # -> app_id, api_key get_score { app_id } # -> reason codes, act on them get_integration_guide {} # -> wire the SDK, open a PR ── human ships the release ── top_up { app_id, amount_cents } # -> 402, or a checkout URL for a human create_campaign { ... } get_stats / get_ledger # -> verify all of the above ``` The MCP server card is at [`/mcp/server-card.json`](/mcp/server-card.json), discovered through [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json). ## How long does onboarding take? The integration is minutes. The gate is automated and usually completes in under an hour, except for the email challenge which waits on you. The real constraint is your own release cycle, because the SDK has to arrive in a build you sign and ship yourself. ## What do I need before I start? A signed and notarised macOS build or an Authenticode-signed Windows build, a domain you have owned for at least six months, a download URL that serves the bundle identifier you declare, and an email address you can answer a challenge on. That is the whole list. ## Do I need to talk to anyone? No. There is no sales process and no onboarding call. The rate card is published, the gate is automated, and the entire flow is available over MCP. ## What if I fail the gate? You get machine-readable reason codes rather than a rejection email, with eligibility dates where the failure is time-based. Fix what is fixable and the gate re-runs automatically - nothing has to be resubmitted by hand. --- # Desktop app distribution glossary URL: https://ghan.io/glossary/ Updated: 2026-09-22 The vocabulary of desktop app distribution, defined precisely. Several of these terms mean something specific inside GHAN that differs from how mobile ad networks use them, and the differences are where the arguments happen. ## Attribution and measurement **Cleared install** — An install that was deterministically attributed, claimed with the receiving app's own signature, and still present and in use 48 hours later. The only unit GHAN bills for. **Install claim** — The signed message the receiving SDK sends on first run when it finds an attribution token, carrying the device signals used for fraud checks. **Deterministic attribution** — Crediting a source only when a unique identifier issued at click time is presented back at install time and verified. Contrast with probabilistic attribution. **Probabilistic attribution** — Inferring the link between a click and an install from signals like IP address, screen resolution, OS version and timing. Always produces an answer, including when there is nothing to find. Banned in GHAN. **Fingerprinting** — Building a quasi-identifier from device characteristics in order to recognise the same machine later. Banned in GHAN, with no fallback. **CTIT (click-to-install time)** — The interval between the click that issued a token and the claim that redeemed it. Its distribution is a primary fraud signal. **Event chain** — The full record of one GHAN transaction as it moves through `impression`, `click`, `install_claim`, `activated_48h`, and either `cleared` or `rejected`. **Double signing** — The requirement that both the serving app's SDK and the receiving app's SDK independently sign before a chain can advance past the claim. Neither party can produce the other's signature. **Canary probe** — A signed liveness request from the server that the SDK answers with its own signature, proving a placement slot is genuinely live in a shipped build rather than merely declared. ## Money **CPI (cost per install)** — The price of one install. On GHAN it is fixed per category by a published rate card and paid only on cleared installs. **Credit** — GHAN's unit of account. One credit is one euro cent. **Credit bonus** — The 1.2 multiplier applied when a serving app takes its earnings as credits rather than cash, turning 70 percent of the CPI into 84 percent of the CPI in spending power. **Escrow hold** — The ledger entry that moves an advertiser's credits out of their spendable balance when an install is claimed, before anyone has earned anything. **Escrow release** — The entry that pays the serving app once the chain clears at 48 hours. Its opposite is an automatic refund when the chain dies. **Clawback** — A reversal recorded after clearing, when fraud is detected later. Always a new ledger line, never an edit. **Append-only ledger** — A ledger where `UPDATE`, `DELETE` and `TRUNCATE` are blocked at the database level, so every correction is a new line and the history of a disagreement survives. **Take rate** — The share the network keeps. GHAN's is 30 percent. ## Placement **Lifecycle slot** — One of GHAN's five in-app placement moments: `install_complete`, `first_success`, `update`, `idle`, `uninstall_intent`. **Installer-time placement** — An offer shown inside a software installer. The pattern that got the previous generation of desktop bundling networks flagged as malware. GHAN has none. **Templated creative** — A placement whose visual form is fixed by the network and rendered by its own SDK: icon, name, one line, install button. Partners supply data, never markup. **Bundleware** — Additional software installed alongside software the person asked for, typically through a pre-checked installer option. Distinct from a post-install recommendation that requires a deliberate click and a separate installer run. **Kill switch** — The server-side control that disables every placement for an app instantly, honoured by the SDK on its next fetch, with no release required. ## Vetting and trust **Gate** — The automated pass-or-fail checks an app must satisfy before it can trade: code signature, malware scan, domain age, contact verification, binary identity. **Reputation score** — A 0-100 pre-trading score weighted 50 percent AI visibility and sentiment, 20 percent release cadence, 20 percent reviews and video coverage, 10 percent domain and social coherence. **Behaviour score** — The post-trading score that replaces reputation after 500 installs, built from retention, uninstall rate, canary compliance and complaint rate. **Share of voice** — An app's proportion of all brand mentions in AI answers to a set of category prompts, measured against its actual rivals. Half of GHAN's reputation score. **Pair cap** — The EUR 500 per month limit on net flow between any two apps until both have behaviour scores, which makes two-app collusion unprofitable. **Pair collusion** — Two apps sending each other installs to extract network payouts rather than to acquire users. **Install farm** — Infrastructure that manufactures installs at scale, usually detectable because the claiming IP belongs to a hosting provider's autonomous system rather than a consumer ISP. ## Interfaces **MCP (Model Context Protocol)** — The protocol GHAN ships every write capability on before shipping it anywhere else, so an agent can operate the network without a browser. **x402** — The revival of HTTP 402 Payment Required as a machine-payable challenge, used by GHAN's top-up endpoint so an agent can fund a wallet without a human clicking Stripe. **llms.txt** — A plain-text file at a site root that gives models a curated index and the key facts, rather than leaving them to infer both from rendered HTML. ## What is the difference between an install and a cleared install? An install is a piece of software arriving on a machine. A cleared install is one that was attributed by a valid single-use signed token, claimed by the receiving app with its own signature, and still present and in use 48 hours later. GHAN bills only for the second kind, which is why its install counts are lower than a network that bills the first kind and its cost per retained user is lower too. ## What does CTIT stand for? Click-to-install time - the interval between the click that issued an attribution token and the claim that redeemed it. Its distribution is one of the strongest available fraud signals, because real human downloads produce a broad right-skewed curve and automated claims do not. ## What is deterministic attribution in one sentence? Attribution that credits a source only when a unique identifier issued at click time is presented back at install time and cryptographically verified, with no inference and no fallback. --- # Desktop cross-promotion networks — a complete guide URL: https://ghan.io/guides/desktop-cross-promotion-network/ Updated: 2026-09-22 A desktop cross-promotion network lets macOS and Windows apps show each other’s install recommendations and settle at a price per install. This guide covers the data exchanged, integration on each platform, and the alternatives. ## What a desktop cross-promotion network is A desktop cross-promotion network is a system in which independent macOS and Windows applications show each other's install recommendations to their own users, and settle that exchange at a price per install. Each member is on both sides of the trade. When your app shows another member's card, you are a seller of attention. When another member shows yours, you are a buyer of installs. In the steady state an app that serves as much as it buys never spends cash at all. This is distinct from three adjacent things: - **A paid CPI network** buys installs from traffic sources it does not own, usually priced by auction. - **An app store or curated bundle** is a destination people browse, and it holds the customer relationship. - **Installer bundling** places offers inside an installer. That is the mechanism that got the previous generation of desktop networks classified as malware, and no current network should be doing it. See [why install networks die](/blog/why-install-networks-die/). ## The full flow, from impression to cleared install | Stage | What happens | What is exchanged | |---|---|---| | Impression | The host app calls a lifecycle slot; the SDK renders a templated card | Partner app id, icon URL, name, one line of copy | | Click | The person clicks Install | A single-use token: nonce, 15-minute expiry, bound to campaign and serving app | | Handoff | The partner's download URL opens | Token travels by `ghan://` protocol handler **and** a local handoff file | | Install claim | The receiving SDK finds the token on first run | Token + the receiving app's own ed25519 signature + VM flags, OS install age, salted hardware hash, clock skew | | Escrow | Credits move out of the advertiser's balance | Ledger line: `escrow_hold` | | Clearing (48h) | The receiving SDK confirms the app is still in use | Coarse usage counters — session starts and ends, feature counts | | Settled | Escrow releases, the serving app earns | Ledger lines: `escrow_release`, `earn` | | Or rejected | Any check fails | Hold refunded automatically, reason code exposed to both parties | Nothing personal is exchanged at any stage. The attribution is a token, not an identity, which is the reason the system can work without fingerprinting. ## Eligibility | Check | Requirement | |---|---| | Code signature | macOS notarisation ticket, or a valid Windows Authenticode chain | | Malware | No malicious or suspicious VirusTotal detections above threshold | | Domain age | At least six months, verified over RDAP | | Contact | An email address that answers a challenge | | Binary identity | The download URL serves the bundle id you declared | All five re-run weekly. Failures come back as machine-readable codes with eligibility dates. Full detail: [vetting and scoring](/vetting/). ## Integration by platform ### Electron ```js import { ghan } from '@ghan/sdk' await ghan.init({ appId: process.env.GHAN_APP_ID, consent: settings.analyticsConsent, maxPerWeek: 1, }) await ghan.slot('first_success') ``` Register the protocol handler in your builder config: ```json { "protocols": [{ "name": "GHAN", "schemes": ["ghan"] }] } ``` ### Tauri Identical SDK, identical calls. The one difference is the deep link: configure the Tauri deep-link plugin for the `ghan` scheme so the attribution token survives the click. ```json { "plugins": { "deep-link": { "desktop": { "schemes": ["ghan"] } } } } ``` ```js import { ghan } from '@ghan/sdk' await ghan.init({ appId: import.meta.env.VITE_GHAN_APP_ID, consent: hasConsent }) await ghan.slot('first_success') ``` If the deep link is not registered, the local handoff file still carries the token and attribution still works — the rate is simply lower. ### Windows Same SDK for Electron and Tauri builds on Windows. Register the URI scheme under `HKEY_CLASSES_ROOT\ghan` with a `URL Protocol` value; most Electron and Tauri packagers do this for you from the config above. The gate checks an Authenticode chain rather than a notarisation ticket. ### macOS Declare the scheme in `Info.plist` via `CFBundleURLTypes` — again, usually generated by your packager. The gate checks the notarisation ticket by fetching your published DMG and validating it, so the URL you register has to be the one you actually ship. ### Node desktop apps Supported. There is no native Swift or C# SDK yet, and the [status page](/status/) says so rather than implying otherwise. ## Cross-promotion compared to the alternatives | | Cross-promotion (GHAN) | Paid CPI network | App store | Subscription bundle | |---|---|---|---|---| | Inventory | Other members' own users | Bought traffic | Store browsers | Bundle subscribers | | Pricing | Published floor, optional bidding above it | Auction with no floor | Free listing, 15–30% of sales | Revenue share | | Billed on | Install still in use at 48h | Usually the install event | A sale | Usage | | Can you pay in non-cash | Yes — serve to earn credits | No | n/a | n/a | | Who owns the customer | You | You | The store | The bundle | | Attribution | Signed single-use token | Often probabilistic | n/a | n/a | | Creative control | None — templated | Full | Listing copy | Listing copy | | Suits | Apps with an existing audience | Funded acquisition | Discovery-led apps | Secondary purchases | A longer, Mac-specific version of this decision is at [Mac app distribution platforms compared](/compare/mac-app-distribution-platforms/). ## When cross-promotion is the wrong answer It needs you to already have users. It converts attention you have into users you do not, at a fixed exchange rate. If you launched last week with three hundred installs there is nothing to trade, and the six-month domain-age requirement in the gate would rule you out anyway. The honest sequence is: launch, community, content, and then cross-promotion once there is an audience worth trading. ## Next - [How it works](/how-it-works/) — the event chain and the escrow flow in full - [SDK quickstart](/docs/sdk/) — every option the SDK takes - [Pricing](/pricing/) — the published rate card - [Install safety and fraud research](/research/desktop-install-network-safety-and-fraud/) — the safety standard in writing ## What is a desktop cross-promotion network? A desktop cross-promotion network is a system in which independent macOS and Windows applications show each other's install recommendations to their own users and settle the exchange at an agreed price per install. Each member is both a seller of attention and a buyer of installs. GHAN is one - member apps render templated partner cards inside their own in-app lifecycle moments, attribution uses single-use signed tokens rather than fingerprinting, and money clears only after a referred install has survived 48 hours. ## Is there a cross-promotion SDK for Tauri apps? Yes. The GHAN SDK, @ghan/sdk, supports Tauri alongside Electron and plain Node desktop applications. Integration is npm install @ghan/sdk, a ghan.init call with your app id and consent state, and a ghan.slot call at whichever lifecycle moment you choose. Tauri needs its deep-link plugin configured for the ghan:// scheme so the attribution token survives the click; everything else is identical to Electron. ## Is there a cross-promotion network for Electron apps? Yes, and Electron is the primary target of version 1 because it is the bulk of indie desktop software. The integration is a single dependency and two calls, and the SDK renders GHAN's own templated card inside your existing UI layer rather than opening a window or injecting markup. ## What are the eligibility requirements to join? Five automated checks. A notarised macOS build or a valid Windows Authenticode chain, a clean VirusTotal result, a domain registered at least six months ago verified over RDAP, a contact email that answers a challenge message, and a download URL that serves the bundle identifier you declared. All five are re-run weekly, so eligibility is a continuing condition rather than an entry ritual. ## What data is exchanged when an install happens? At click, a single-use token with a nonce and a 15-minute expiry, bound to the campaign and the serving app. At install, the receiving SDK returns that token with its own ed25519 signature plus fraud signals - virtual-machine indicators, operating-system install age, a salted hardware hash, and clock skew. At clearing, coarse usage counters showing the app was still in use 48 hours later. No file contents, no personal data, no raw hardware identifiers. ## How is cross-promotion different from a paid CPI network? A paid CPI network sells you installs from traffic sources you do not own, priced by auction, usually billed on the install event. A cross-promotion network trades installs between members, so the inventory is other products' own users, and the price can be paid in attention rather than cash. GHAN prices from a published floor that never rises, with optional second-price bidding for priority above it, and bills only on installs that survive 48 hours. --- # GHAN guides URL: https://ghan.io/guides/ Updated: 2026-09-22 Guides are the long, practical documents — what something is, how to do it, and what it costs. Shorter reference material lives in the docs, and the arguments live on the blog. - [Desktop cross-promotion networks — a complete guide](/guides/desktop-cross-promotion-network/) — what one is, integration for Tauri, Electron, Windows and macOS, eligibility, the full install flow, and how it compares to paid CPI, app stores and bundles. More to come. The [documentation](/docs/) covers the reference material, and the [blog](/blog/) carries the arguments. ## Where should I start? With the desktop cross-promotion network guide if you want to understand the category and the integration, or with the SDK quickstart if you have already decided and just want the code. --- # How GHAN works URL: https://ghan.io/how-it-works/ Updated: 2026-09-22 An install moves through GHAN as an event chain with six states. Each state transition requires cryptographic proof, money is held in escrow between claim and clearing, and any chain that cannot prove itself is refunded automatically rather than argued about. ## The six states of an event chain Every GHAN transaction is one row in `event_chains` that moves through a state machine. It can only move forward, and each move has a precondition that must be proven, not asserted. | State | What has to be true to enter it | |---|---| | `impression` | The serving SDK rendered a templated card and signed the render event | | `click` | The person clicked; a single-use token was issued with a 15-minute expiry | | `install_claim` | The receiving SDK found the token on first run and signed a claim with its own key | | `activated_48h` | 48 hours later the receiving app is still installed and has been used | | `cleared` | Escrow released, the serving app earned, the ledger line is final | | `rejected` | A fraud rule or a missing signature killed the chain; the hold is refunded | A chain cannot advance past `install_claim` with a single signature. The serving app's signature proves the placement happened; the receiving app's signature proves the install happened. Neither party can produce the other's. ## Step by step ### 1. The host app decides a moment has arrived GHAN never decides when to interrupt someone. The host application calls `ghan.slot('first_success')` — or any of the other four [lifecycle slots](/lifecycle-slots/) — at a moment it considers appropriate. If the host never calls, GHAN never renders. ### 2. The SDK fetches a signed placement The server returns a signed placement payload: a partner app id, an icon URL, a name, and one generated line of copy. It never returns HTML, JavaScript or a custom image. The SDK renders the card itself in the host application's own UI layer, which is why a GHAN card cannot carry a payload. ### 3. The impression is signed and recorded The SDK signs the impression with the ed25519 private key it generated on first run and stored in the app data directory. That key never leaves the machine; only the public key was ever registered. ### 4. A click issues a single-use token If the person clicks, the server issues a token with a nonce, a 15-minute expiry and a unique constraint on use. The partner's download URL opens with the token in the URL fragment, and the token is also written to a local handoff file that the partner's SDK reads on first run — because a browser download followed by a manual install loses the fragment. ### 5. The receiving app claims On first run the partner's SDK looks for the token, via the `ghan://` protocol handler and the handoff file. It signs an `install_claim` with its own key and sends device signals alongside it: virtual-machine indicators, operating-system install age, a salted hardware hash that is never the raw value, and clock skew. At this instant the advertiser's credits are charged and moved into escrow. No money has moved to anyone yet. ### 6. Forty-eight hours later, behaviour decides The receiving SDK reports coarse usage counters — session starts and ends, feature counts, never content and never personal data. If the application is still present and has been used, the chain enters `activated_48h`, escrow releases, and the serving app earns. If it has not, the hold refunds and the chain ends in `rejected` with a reason code the serving app can read through `get_stats`. Transparency applies to rejections too; a partner always learns why they were not paid. ## Where the money sits at each moment 1. **Before the claim** — the advertiser's credits are in their wallet. Nothing is reserved. 2. **At `install_claim`** — `escrow_hold` moves the CPI out of the wallet into escrow. The ledger records it. 3. **At `activated_48h`** — `escrow_release` plus `earn` credit the serving app with 70 percent of the CPI, or 84 percent of the value in credits. GHAN keeps 30 percent. 4. **At `rejected`** — the hold reverses. The ledger records the reversal as a new line; nothing is ever edited. The `ledger` table blocks `UPDATE`, `DELETE` and `TRUNCATE` with a database trigger. A correction in GHAN is always a new line, never a rewritten one. That is what makes `get_ledger` worth reading. ## The three scoring layers Before an app can trade at all it has to pass a [vetting gate](/vetting/), and after it starts trading its behaviour replaces its reputation: - **Gate** — pass or fail, automated, run on registration and again weekly. Notarisation or Authenticode, a clean malware scan, a domain at least six months old, a verified contact email, and a download URL that serves the bundle id it declared. - **Reputation** — a 0-100 score built from AI visibility and sentiment, release cadence, reviews, and domain and social coherence. It is what GHAN knows about an app before it has traded anything. - **Behaviour** — after 500 installs traded, this replaces reputation entirely. Retention of referred installs, uninstall rate, canary compliance, complaint rate. ## What a partner's agent can verify without asking - `get_ledger` returns raw signed lines with event-chain references. - `get_stats` returns impressions, clicks, installs, cleared installs, retention and fraud rejections with reason codes. - `get_network_stats` returns the published network-wide numbers — average CPI by category, clearing rate, fraud percentage. - `get_score` returns the score breakdown with machine-readable reasons for every gate failure. Every milestone GHAN ships has the same acceptance rule: a partner's agent must be able to verify the claim from those outputs alone. ## How long does it take for an install to clear? A standard install clears 48 hours after the claim, once the receiving SDK has confirmed the application is still present and has been used. Pairs of apps trading more than EUR 500 per day with each other clear on day-7 engagement instead, which is a slower and stricter bar applied exactly where the incentive to cheat is largest. ## What happens if the referred user uninstalls within 48 hours? Nothing clears and nobody is billed. The escrow hold placed at install_claim is released back to the advertiser automatically. The serving app earns nothing for that chain. This is the single most important design decision in GHAN - payout follows behaviour, never the install event. ## Can a serving app fake installs to earn credits? It would have to forge two independent ed25519 signatures, one of which belongs to an SDK running inside another company's signed binary, then survive a click-to-install-time histogram, a device check that reads the ASN of the claiming IP, and a cohort retention curve compared against the category baseline. The cost of faking a cleared install is designed to exceed the payout for it, which is the test every monetised feature in GHAN has to pass before it ships. ## Does GHAN work if my app is offline most of the time? Yes. Events are signed locally and queued, then delivered when connectivity returns. Token expiry is 15 minutes from issue, so a click made offline will not clear, but impressions, usage heartbeats and install claims all tolerate delayed delivery. --- # The audited cross-promotion network for desktop apps URL: https://ghan.io/ Updated: 2026-09-22 GHAN is a cross-promotion and paid-install network for desktop apps. Cost per install is a fixed published price - EUR 12-50 by category - charged only when a referred install is still in use 48 hours later. The problem ## Desktop software has no distribution layer. No store that matters. No organic discovery surface. No shelf. So every founder shipping a DMG or an EXE ends up bidding for the same clicks as companies with ten times their lifetime value per customer. **A €29 one-time app** €0.27 Affordable cost per click at a 30% margin, converting at 3%. **A €29/month product** €3.18 Same keyword. Same landing page. Twelve times the budget. **What you already own** 100% Of your users have installed desktop software recently. Roughly nobody else has. The auction is not unfair. It is working — it discovered who values the click most, and it is not you. [The arithmetic in full](/compare/google-ads/). What your users see ## Inside your app. Never inside an installer. A templated card at a moment your own code chose. Partner icon, partner name, one line. The person can ignore it, and nothing installs unless they complete the other app's own installer themselves. Converter — export complete Exported **interview-final.mp4** in 41s. **Sweep**Reclaim disk space after big exports Install via GHAN · first_success slot · dismissible slot chosen by **your code** remote markup **impossible** frequency cap **yours** competitors **excluded** The unit ## Pay for users who stay. Impressions are free. Clicks are free. You are charged when a referred install is still in use 48 hours later, and for nothing else. | One campaign week, creator tool at €24 | Count | Billed | |---|---|---| | Impressions | 40,000 | €0 — never billed | | Clicks | 1,200 | €0 — never billed | | Install claims | 260 | €6,240 into escrow, not charged | | Rejected by a fraud rule | 18 | refunded | | Did not survive 48 hours | 61 | refunded | | **Cleared installs** | **181** | **€4,344** | A network billing on the install event charges for all 260 and still calls it a €24 CPI. Your real cost per retained user was €34.47 — 44% above the headline. [Every definition, and the methodology](/reports/desktop-software-cpi-benchmarks/). Pricing ## A floor that never rises. A market above it. The rate card is a floor, not a ceiling. Anyone can always buy at it. Above it, bidding allocates priority when a category is contested — second price, so you pay one cent over the next bid, never your maximum. **Utilities & consumer** €12–18 Menu-bar tools, cleaners, converters, window managers. Per cleared install, macOS and Windows alike. **Creator tools** €20–30 Screen recorders, editors, design tools, capture apps. **Prosumer & B2B** €35–50 Developer tools, database clients, API clients, team software. network keeps **30%** serving app earns **70%** as credits **84%** reserved at floor **30% of inventory** [The full rate card](/pricing/)[How bidding works](/bidding/) The graveyard ## We watched them burn it all down. OpenCandy, dead 2016. ironSource installcore, flagged by antivirus engines worldwide. AdDuplex, shut down quietly in 2023. Three mechanisms killed them, and every one of the three is optional. ### What they did - Offers placed inside the installer - Paid on the install event - Partners supplied their own creative - Pre-checked boxes and silent installs - Detection attached to the SDK, so careful integrators were flagged too ### What GHAN does - No installer-time slot exists at all - Clears on 48 hours of real retention - Templated cards from a payload with no markup field - No checkbox — a card you can ignore - Every claim checkable from the SDK source [The full post-mortem](/compare/ironsource/) The manifesto ## Eight Commandments. Written before the network had a single member, so they can be held against it afterwards. Each one costs GHAN something to keep. ### I. Know thy buyer They get the click. They keep the person. The install comes from your download URL, activates your licence, appears in your billing system. GHAN never sees your users. ### II. Never be priced out In a search auction the clearing price is the only price. A published floor that never rises, plus 30% of every category reserved at it. The market sets what contention is worth, on top of a guarantee rather than instead of one. ### III. Pay only for the real They charge on tap. The user vanishes, that is your problem. Escrow at claim, released only if the install is still in use 48 hours later. No real usage, full refund, automatically. ### IV. Face no rival You pay a platform to show your competitor to your own users. Category and named-app exclusions, enforced in the SDK inside the build you signed. There is no server field that overrides them. ### V. Earn while thou spends Spend on Google and the money flows one way, out. Serve placements, earn 70% of what cleared — 84% of it in value as credits. An app that serves as much as it buys never touches a card. ### VI. Appear at the perfect moment A rectangle between baby photos and political rants. Or: inside a relevant desktop app, right after the person finished a task successfully. Five lifecycle slots, none of them an installer. ### VII. Own what thou builds Stop spending and you lose everything you built there. Stop calling ghan.slot, request a payout, ship the next build without the dependency. Nothing here is load-bearing in your product. ### VIII. Never punish the small €100k/month gets premium. €500 gets scraps. Same floor for everyone. No enterprise tier, no volume discount, no negotiated rate. The reserved 30% exists so scale cannot buy out a category. [What each one costs us](/manifesto/) Integration ## One dependency. Two calls. The SDK generates its own ed25519 keypair on first run, renders slots when your code asks, and emits nothing at all before your app reports consent. ```js import { ghan } from '@ghan/sdk' await ghan.init({ appId: process.env.GHAN_APP_ID, consent: settings.analyticsConsent, // nothing emitted while false exclude: ['com.competitor.app'], // never show these maxPerWeek: 1, // your cap, not ours }) // You choose the moment. Nothing renders unless you call this. await ghan.slot('first_success') ``` [Get started](/get-started/)[SDK quickstart](/docs/sdk/) The referee ## Nine layers between a member app and a bad install. Any one of them failing does not open the network, because they defend different things. 1 · GateNotarisation or Authenticode, clean malware scan, domain age over six months, verified contact, matching bundle id. Re-run weekly. 2 · PlacementTemplated cards only. No installer slot. No remote markup — the payload has no field for it. 3 · AttributionSingle-use signed tokens, 15-minute expiry, two independent signatures required. 4 · DeviceVM indicators, OS install age, salted hardware hash, clock skew, datacenter ASN resolved offline. 5 · Economics48-hour clearing, escrow, pair caps. Cost to fake must exceed the payout. 6 · BehaviourCohort retention shape, signed canary probes, complaint rate. 7 · EnforcementFlag, hold clearing, throttle, suspend and freeze escrow. Plus an instant kill switch. 8 · DataAppend-only ledger proven on a real database, row-level security, pinned TLS, no PII. 9 · DisclosureAll fourteen rejection conditions published with stable reason codes, and a monthly fraud report. [All nine, in detail](/security/) For agents ## Built for the agent, not the dashboard. Every write capability ships in the MCP server before it ships anywhere else. Two moments stay human on purpose: shipping the release, and setting the spend ceiling. ``` get_rate_card {} # public — is this worth doing register_app { ... } # -> app_id, api_key get_score { app_id } # -> reason codes, act on them get_integration_guide {} # -> wire the SDK, open a PR ── human ships the release ── top_up { app_id, amount_cents } # -> 402, or a checkout URL create_campaign { ... } # max_bid_cents optional get_stats / get_ledger # -> verify all of the above ``` [Every MCP tool](/docs/mcp/) Status ## No network statistics on this page. GHAN is pre-launch and in its founding-partner phase. Nothing has traded, so there are no install counts to publish and this site invents none. The referee core — signing, tokens, the event-chain state machine, the append-only ledger — is built and tested against a real Postgres database. [Become a founding partner](/get-started/)[What is built today](/status/) ## What is GHAN? GHAN is a cross-promotion and paid-install network for macOS and Windows desktop applications. Member apps render each other's install cards inside their own in-app lifecycle moments, and settle through a single append-only credit ledger in which both the serving app and the receiving app have cryptographically signed every line. ## Is GHAN bundleware? No. Bundleware means extra software installed alongside the software a person asked for, usually through a pre-checked box in an installer. GHAN never places anything inside an installer. Placements appear after installation, inside the running application, as a card the person can ignore, and nothing installs unless the person clicks through and completes the other app's own installer themselves. ## Which platforms does GHAN support? Desktop only - macOS (DMG) and Windows (EXE). The version 1 SDK targets Electron, Tauri and Node desktop applications. There is no mobile product and no plan for one. ## How much does GHAN cost? There is no subscription and no minimum spend. Advertisers pay a fixed price per cleared install from a published rate card - EUR 12-18 for utilities and consumer apps, EUR 20-30 for creator tools, EUR 35-50 for prosumer and B2B. GHAN keeps 30 percent and the serving app earns the remaining 70 percent, multiplied by 1.2 when taken as network credits. ## How does GHAN prove its numbers are real? Every claim is reproducible from data the partner already holds. The ledger is append-only at the database level, every monetised event carries an independent signature from both apps involved, and the get_ledger MCP tool returns the raw signed lines with their event-chain references. A partner's agent can recompute any published number without asking GHAN to be trusted. --- # The five GHAN lifecycle slots URL: https://ghan.io/lifecycle-slots/ Updated: 2026-09-22 GHAN has exactly five placement slots, all of them inside the running application and none of them inside an installer. The host app calls a slot when it decides a moment has arrived; the SDK renders a templated card with a partner icon, a name and one line, and nothing else is possible. ## The five slots ### `install_complete` Fires on the first launch after installation. The person is demonstrably in install mode — they have just completed one installation voluntarily and the friction of a second one is at its lowest point it will ever be. Renders a single card below the app's own first-run content. Never a modal, never before the host app's own onboarding. ### `first_success` Fires the first time the application does the thing it exists to do — the screenshot is captured, the file is converted, the database connects, the recording is saved. The host app defines what success means, because only the host app knows. This is the highest-trust moment in a desktop application's entire lifecycle and it is the slot most members enable first. ### `update` Fires after an update lands. You have already earned a moment of the person's attention to tell them what changed; a single card beside the release notes costs nothing extra in interruption. ### `idle` Fires at a deliberate pause the host app chooses — a long export, an empty state, a settings screen. The cheapest inventory in the network in interruption terms, and correspondingly the lowest-converting. ### `uninstall_intent` Fires when the person is leaving. The only moment in the list where showing a competing product is unambiguously good for the person rather than merely acceptable, and the one slot where GHAN allows same-category placements by default. ## What a slot renders Always the same shape, always rendered by the SDK inside the host application's own UI layer: - The partner's icon, fetched from a URL on GHAN's CDN - The partner's name - One generated line of copy - An Install button - A dismiss affordance That is the complete list. There is no code path in the SDK that renders remote HTML, remote JavaScript, a video, an animation, or a partner-supplied image outside the icon. This is a property of the implementation rather than a term in an agreement, which matters because agreements are not checkable by a reviewer and code is. ## Calling a slot ```js // Returns immediately and resolves to a result you can ignore. const result = await ghan.slot('first_success') // result.rendered -> boolean, false if capped, excluded or nothing matched // result.chainId -> the event chain, if one was created ``` If GHAN has nothing relevant, if your frequency cap is reached, if the person has dismissed too many cards, or if your kill switch is on, `rendered` is `false` and nothing appears. The host application never has to handle an error to stay safe. ## Slot hygiene the SDK enforces 1. Never two cards in one session. 2. Never a card during the host app's own first-run flow unless `install_complete` was explicitly called there. 3. Never the same partner twice within 30 days to the same install. 4. Never a card to an install that has dismissed three in a row. 5. Never anything while the host app reports consent as false. These are defaults in the SDK, not server policy, which means a partner cannot ask GHAN to relax them for their campaign. ## The canary The server periodically sends a signed liveness probe that the SDK answers with its own signature. That is how GHAN can prove a slot is genuinely live in a shipped build rather than merely declared in a dashboard — and it is how an app claiming inventory it does not have gets suspended. See [fraud prevention](/fraud-prevention/). ## Why are there no installer-time placements? Because installer-time placements are what killed the previous generation of desktop cross-promotion networks. An offer inside an installer competes for the same click as the Next button, which makes accidental acceptance the most profitable outcome for everyone except the person installing. Antivirus vendors correctly treat that pattern as a malware signature. GHAN has no installer-time slot and will not add one. ## Which slot performs best? first_success, by a distance, because it is the only moment where the person has just had a good experience with software and is briefly receptive to more of it. uninstall_intent converts well too, for the opposite reason - a person leaving genuinely wants an alternative, and it is the one moment where showing a competitor is a service rather than a leak. ## Can I add my own slot? Not in version 1. The five slots are fixed because a custom slot is an unbounded surface, and an unbounded surface is how a templated network becomes an ad network. If a sixth moment turns out to be genuinely distinct and genuinely respectful, it becomes a slot for everyone rather than a private extension. ## How often will a card appear? Whatever cap you set. The SDK enforces a host-supplied frequency cap and defaults to conservative. Most members run one card per week or fewer, and the 48-hour clearing rule means an irrelevant card shown often earns less than a relevant card shown rarely. --- # The Eight Commandments URL: https://ghan.io/manifesto/ Updated: 2026-09-22 Eight rules, written before the network had a single member, so they can be held against it afterwards. Each one is a response to a specific thing that was done to desktop developers by an advertising system, and each one costs GHAN something to keep. ## I. Know thy buyer You get a click. They keep the person. On most networks the platform holds the customer relationship and rents you access to it. On GHAN the person installs from **your** download URL, activates **your** licence, and appears in **your** billing system. GHAN never sees your users and holds nothing you would have to ask for back. ## II. Never be priced out > *Revised 22 September 2026. This rule previously read "never enter an auction".* In a search auction the clearing price is the only price. When a better-funded competitor enters your keyword, the floor rises under you until you cannot buy at all. That is the harm — not price discovery itself. So GHAN guarantees a **floor that never rises**, published in code, that any approved advertiser can always buy at. Above the floor there is a second-price market for priority in contested inventory, and **thirty percent of every category is reserved at floor** and never auctioned. You can always buy. You can never be outbid out of the network. The market sets what contention is worth, and it does it on top of a guarantee rather than instead of one. See [bidding](/bidding/). ## III. Pay only for the real They charge on tap. The user vanishes and that is your problem. On GHAN, money moves into escrow when an install is claimed and only leaves it if the install is **still in use 48 hours later**. No real usage, full refund, automatically, with no dispute process because none should be needed. This is the rule that removed installer-time placements and payment-on-the-install-event from the product — which is to say, most of what the previous generation of desktop networks sold. ## IV. Face no rival You pay a platform to show your competitor's advertisement to your own users. Never here. Category exclusions and named-app exclusions are enforced **in the SDK, in the build you compiled and signed**. GHAN cannot override them from the server, because there is no server field that does. The one exception is `uninstall_intent`, where same-category placements are allowed by default — the person is leaving, and an alternative is genuinely a service to them at that moment. You can turn it off. ## V. Earn while thou spends Spend on Google and the money flows one way, out, forever. Serve placements and you earn 70 percent of what cleared — or 84 percent of it in value if you take [credits](/pricing/). An app that serves as much as it buys never touches a card. That is the intended steady state, and the credit bonus exists to make it the cheapest one. ## VI. Appear at the perfect moment A rectangle between baby photos and political rants. Or: inside a relevant desktop application, at a moment that application chose, right after the person finished a task successfully. GHAN has five [lifecycle slots](/lifecycle-slots/) and none of them is an installer. The host app calls a slot or nothing renders. ## VII. Own what thou builds Stop spending on a platform and you lose everything you built there. The SDK ships in your own signed release. The kill switch is one call. Your users are yours, your licences are yours, your list is yours. Leave tomorrow and take all of it: stop calling `ghan.slot`, request a payout, ship the next build without the dependency. Nothing about GHAN is load-bearing in your product. ## VIII. Never punish the small A EUR 100,000 monthly buyer gets premium placement and a EUR 500 buyer gets scraps. Not here. The floor is the same price for everyone, there is no enterprise tier, there is no volume discount, and there is no rate you can negotiate that is not on the [pricing page](/pricing/). The reserved thirty percent exists precisely so that scale cannot buy out the whole of a category. Five thousand passionate users beat five hundred thousand passive ones, and the pricing should not pretend otherwise. --- ## What these cost A manifesto that costs nothing to keep is a marketing page. These are the prices: - **III** removed the highest-volume inventory on desktop and the fastest-clearing revenue model, and made GHAN carry 48 hours of settlement risk. - **IV** removed competitor placements, which are the highest-converting inventory an advertising network has. - **VIII** removed the enterprise tier, the volume discount and the negotiated rate — which is to say, the entire enterprise sales motion. - **II**, in its revised form, caps how much a contested category can ever earn the network, because thirty percent of it is permanently sold at floor. If a future version of GHAN quietly drops one of these, this page is the record that it did. ## Why did Commandment II change? It originally read "never enter an auction". That was half right and imprecisely aimed. What harms a small desktop app is not price discovery, it is that in a search auction the clearing price becomes the only price, so the floor rises until you cannot buy at all. The rule now reads "never be priced out", and it is kept by a published floor that never rises plus a reserved tranche of inventory that is never auctioned. The protection is stronger than the original wording and the market above it is real. See /bidding/. ## Are these enforceable or just marketing? Some are enforceable by implementation, which is the only kind that survives revenue pressure. "Face no rival" is a category exclusion enforced in the SDK in your own build. "Pay only for the real" is the 48-hour clearing rule in the ledger. "Never be priced out" is a floor constant in code with a reserved inventory tranche. Others - "know thy buyer", "own what thou builds" - are commitments, and they are written here so a partner can hold GHAN to them in public. ## What has a commandment actually cost GHAN? Commandment III removed installer-time placements and payment on the install event, which is most of the volume and most of the revenue the previous generation of networks had. Commandment IV means GHAN cannot sell a competitor placement into your app, which is the highest-converting inventory an ad network has. Commandment VIII means a EUR 100,000 buyer and a EUR 500 buyer get the same floor price, so there is no enterprise tier to sell. --- # GHAN pricing and rate card URL: https://ghan.io/pricing/ Updated: 2026-09-22 GHAN charges per cleared install at a published floor price set by the category of the app being installed. The floor never rises and anyone can always buy at it; above it, advertisers may bid for priority in contested inventory. No subscription, no minimum spend, 30 percent network fee. ## The rate card These are **floor** prices, not fixed prices. Any approved advertiser can always buy at them, and the floor never rises. Above it, [bidding](/bidding/) allocates priority when a category is contested. Prices are per **cleared** install — an install that was deterministically attributed and was still in use 48 hours later. Installs that do not clear are refunded and cost nothing. | Category | Per cleared install | Typical members | |---|---|---| | Utilities and consumer | EUR 12–18 | Menu-bar utilities, cleaners, converters, window managers | | Creator tools | EUR 20–30 | Screen recorders, editors, design tools, capture apps | | Prosumer and B2B | EUR 35–50 | Developer tools, database clients, API clients, team software | The card is stored in `packages/shared/ratecard.ts`, published through the `get_rate_card` MCP tool, and changing it is a versioned change that partners can see. There is no rate you can *negotiate* that is not on this page — the only way to pay more is to bid publicly for priority, and the only way to pay less does not exist. ## The split For every cleared install: - The **advertiser** pays the CPI for their category. - The **serving app** earns 70 percent of it. - **GHAN** keeps 30 percent, which pays for the vetting, the fraud pipeline, the escrow and the settlement. If the serving app takes its earning as network credits instead of cash, the amount is multiplied by **1.2** — so 70 percent of the CPI becomes 84 percent of the CPI in spending power inside the network. ### A worked example A creator tool priced at EUR 24 per cleared install: | Line | Amount | |---|---| | Advertiser is charged at `install_claim` (escrow hold) | EUR 24.00 | | Chain clears at 48 hours | — | | Serving app earns, cash | EUR 16.80 | | Serving app earns, taken as credits | EUR 20.16 of spending power | | GHAN keeps | EUR 7.20 | If that install had not survived 48 hours, every number in that table would be zero and the EUR 24 would be back in the advertiser's wallet. ## Credits One credit is one euro cent. Credits are the single unit of account in the network: - **Top up** with cash through Stripe Checkout, or machine-to-machine over x402 with USDC on Base if your agent is paying. - **Earn** by serving placements that clear. - **Spend** on your own campaigns at the published rate. - **Cash out** through Stripe Connect once the balance reaches EUR 50, paid monthly. An app that serves as much as it buys never touches a card. That is the intended steady state of the network, and the credit bonus exists to make it the cheapest one. ## What you are not charged for - Impressions. Free, unlimited, never billed. - Clicks. Free. A click that never becomes a surviving install costs nothing. - Installs that fail the 48-hour retention check. - Installs rejected by any fraud rule — token reuse, expiry, VM or datacenter signals, click-to-install-time anomalies. - Chains that die for any reason at all. The default on ambiguity is refund. ## Bidding above the floor Optional, and most members will never use it. Set `max_bid_cents` on a campaign and you compete for priority in contested inventory at **second price** — you pay one cent above the next-highest competing bid, never your own maximum. Leave it unset and you buy at floor forever. Three things the floor guarantees regardless of what anyone bids: 1. **The floor never rises.** It is a constant in code, changed only as a versioned, announced change. 2. **Thirty percent of every category is reserved** at floor price and is never auctioned. 3. **Pair caps still bind.** A bid cannot buy its way out of a fraud control. The serving app earns 70 percent of the price that *cleared*, not of the floor — which is how an app with genuinely good inventory ends up earning more than one without. Full mechanism: [bidding](/bidding/). ## Pair caps Until both apps in a pair have a behaviour score, the net flow between them is capped at **EUR 500 per month**. Above EUR 500 per day, a pair clears on day-7 engagement rather than 48-hour retention. These caps are not a pricing tier and cannot be bought out. They exist because two colluding apps are the cheapest attack on any two-sided install network, and a cap plus a slower clearing bar makes the attack unprofitable rather than merely detectable. Read [fraud prevention](/fraud-prevention/) for the rest of the ladder. ## Deposits and KYC - Apps with no trading history buying above a small volume post a refundable **EUR 250** deposit, returned after 1000 cleared installs with clean retention. - Apps with zero history buying more than EUR 1000 per month complete Stripe Identity verification. - Payouts run through Stripe Connect Express, monthly, at a EUR 50 minimum. ## Getting a price without talking to anyone ``` get_rate_card {} ``` That MCP tool is public and unauthenticated. So is `get_network_stats`. You do not need an account, a sales call or an email address to know exactly what GHAN costs. ## What does a cleared install mean? A cleared install is a referred install that was attributed by a valid single-use token, claimed by the receiving app with its own signature, and still present and in use 48 hours later. Installs that do not survive that window are refunded to the advertiser automatically and cost nothing. ## Is the rate card a floor or a fixed price? A floor. Any approved advertiser can always buy at the published price and the floor never rises, which is the protection a one-time-licence app actually needs. Above the floor there is a second-price auction for priority when a category is contested, and thirty percent of every category is reserved at floor and never auctioned. A purely fixed price cannot clear a market or reward the apps supplying the best inventory; a floor plus a market above it does both. See /bidding/. ## What is the 1.2x credit bonus? A serving app earns 70 percent of the CPI. If it takes that earning as network credits rather than a cash payout, the amount is multiplied by 1.2, so 70 percent of CPI becomes 84 percent of CPI in spending power. Credits keep value inside the network and cost GHAN less to settle than a bank transfer, so the bonus is shared back. ## Is there a minimum spend or subscription? No. There is no subscription, no seat licence and no minimum spend. You top up a credit balance and spend it, or you earn credits by serving placements and never pay cash at all. ## What is the refundable deposit for? Apps with no trading history that want to buy more than a small volume immediately post a refundable EUR 250 deposit. It is returned after 1000 cleared installs with clean retention. It exists because the cheapest attack on any install network is a funded buyer colluding with a seller, and a deposit makes the first round of that attack cost real money. --- # GHAN privacy policy URL: https://ghan.io/privacy/ Updated: 2026-09-22 GHAN processes behavioural counters and install-fraud signals. It does not process file contents, window titles, clipboard data, raw hardware identifiers or any directly identifying field, and the SDK emits nothing at all until the host application reports consent. **Effective 22 September 2026.** GHAN is operated by the entity named on the [contact page](/contact/). Questions: `hello@ghan.io`. ## Who this covers Two different groups, with different relationships to GHAN: 1. **Member apps and their contacts** — the developers who register applications. GHAN is a controller for this data. 2. **End users of member apps** — people who use software containing the GHAN SDK. The member app is the controller; GHAN is a processor acting on its instructions. See the [DPA](/dpa/). ## What is processed ### From member apps Application name, bundle identifier, platform, domain, download URL, contact email, code-signing status, malware scan results, payment and payout details held by Stripe, and the full ledger and event history of the account. ### From end users of member apps, after consent - Session start and end timestamps - Coarse feature counters defined by the member app - Whether a rendered card was dismissed ### From end users of member apps, at install claim, as a fraud signal - Virtual machine and hypervisor indicators - Operating-system install age - A **salted** hardware hash — the raw identifier is never transmitted or stored - Clock skew against the server - Country and autonomous system of the claiming IP, resolved from a local offline database ## What is never processed File names, file contents, file paths, window titles, clipboard contents, keystrokes, screen contents, raw hardware identifiers, MAC addresses, device serial numbers, advertising identifiers, cross-application identity, browsing history, or anything outside the host application. ## Legal bases | Data | Basis | |---|---| | Member app and contact data | Performance of a contract | | Install-fraud signals | Legitimate interest in preventing payment fraud | | Behavioural counters | Consent, collected by the member app and passed to the SDK | | Ledger and event records | Legal obligation and legitimate interest in maintaining auditable financial records | ## Retention | Data | Retained | |---|---| | Event chains and signatures | As long as the ledger line they justify | | Behavioural counters | Aggregated after 90 days | | Device fraud signals | 180 days, then discarded | | Member account data | Duration of the account plus statutory retention | ## Sharing - **Stripe** — payments, payouts and identity verification. - **Supabase** — database hosting within the EU. - **VirusTotal** — binary hashes submitted for the malware gate. Binaries, not user data. - No advertising networks, no data brokers, no analytics resale. Ever. ## Rights Access, rectification, erasure, restriction, portability and objection. For end users of member applications, exercise these with the member app, which is the controller; GHAN will assist that app as its processor. Contact `hello@ghan.io`. ## Transfers Primary processing is in the EU. Where a processor operates outside it, transfers rely on standard contractual clauses. ## Changes Material changes are announced in the [changelog](/changelog/) and its [RSS feed](/feed.xml) before they take effect. ## Does GHAN track individual users? No. GHAN's attribution is deterministic - a single-use signed token rather than an identity - which means the system does not need to recognise a person and is not built to. The device signals attached to an install claim exist to kill fraudulent chains and are deliberately worse at identifying a person than the fingerprinting GHAN refuses to perform. ## What is the legal basis for processing? For member apps and their contacts, performance of a contract. For install-fraud signals, legitimate interest in preventing payment fraud, which is a narrow and well-established basis. For behavioural telemetry, the consent the host application collects and passes to the SDK, and nothing is emitted before it is true. ## How long is data retained? Event chains and their signatures are retained for as long as the ledger line they justify, because an append-only ledger whose evidence had been deleted would not be auditable. Behavioural counters are aggregated after 90 days. Device signals are retained for 180 days for fraud investigation and then discarded. --- # Desktop software CPI benchmarks and rates URL: https://ghan.io/reports/desktop-software-cpi-benchmarks/ Updated: 2026-09-22 Cost per install for desktop software is close to meaningless until you know which installs it counts. GHAN’s published rates are EUR 12-18, EUR 20-30 and EUR 35-50 per install still in use 48 hours later. ## The published rates Per **cleared** install — attributed by a single-use signed token, countersigned by the receiving application, and still in use 48 hours after the claim. | Category | Per cleared install | macOS | Windows | Examples | |---|---|---|---|---| | Utilities and consumer | EUR 12–18 | Same | Same | Menu-bar tools, cleaners, converters, window managers | | Creator tools | EUR 20–30 | Same | Same | Screen recorders, editors, design tools, capture apps | | Prosumer and B2B | EUR 35–50 | Same | Same | Developer tools, database clients, API clients, team software | **Network fee:** 30%. **Serving app earns:** 70% of the price that cleared, or 84% of it in value if taken as credits. **Currency:** EUR, integer cents. **Auction:** second price, above the floor only, 30% of inventory reserved at floor. These are facts about GHAN's prices, fixed in `packages/shared/ratecard.ts` and returned by the public, unauthenticated `get_rate_card` tool. They are not estimates of a market rate. ## How cost per install works for desktop software An advertiser pays a price each time their application is installed as a result of a placement. Two questions decide whether any given CPI rate is good, and neither is the number itself. **Question one: what counts as an install?** A network that bills on the install event charges you for software landing on a disk. A network that bills on retention charges you for software still being used. Those are different products at the same nominal price. **Question two: who sets the price, and is there a floor?** In an auction with no floor the clearing price *is* the price, so a funded competitor arriving in your category prices you out entirely. GHAN publishes a floor that never rises and that anyone can always buy at, and runs a second-price market only for priority above it, with 30 percent of each category reserved at floor. Price discovery is not the problem; price discovery with no floor is. See [bidding](/bidding/). ### A worked calculation A creator tool advertising at EUR 24 per cleared install, over one campaign week: | Metric | Count | Billed | |---|---|---| | Impressions | 40,000 | EUR 0 — never billed | | Clicks | 1,200 | EUR 0 — never billed | | Install claims received | 260 | EUR 0 at this stage; 260 × EUR 24 moves into escrow | | Rejected by a fraud rule | 18 | EUR 0 — holds refunded | | Did not survive to 48 hours | 61 | EUR 0 — holds refunded | | **Cleared installs** | **181** | **EUR 4,344** | | Effective cost per install claim | — | EUR 16.71 | | Effective cost per retained user | — | EUR 24.00 | The two effective figures at the bottom are the ones worth carrying between networks. A network billing on the install event would have charged for all 260 and reported a EUR 24 CPI — while your actual cost per retained user was **EUR 34.47**, 44 percent higher than the headline. These counts are an illustration of the arithmetic, not observed GHAN data. GHAN has not traded yet. ## Definitions | Term | Definition | |---|---| | **Impression** | A templated card rendered by the SDK in a member application, signed by that app's key. Never billed. | | **Click** | A person activated the card; a single-use token was issued with a 15-minute expiry. Never billed. | | **Install** | The application arrived on a machine. On its own this is not a billable event on GHAN. | | **Install claim** | The receiving SDK found the token on first run and signed a claim with its own key. Triggers an escrow hold, not a charge. | | **Cleared install** | An install claim that survived to 48 hours of real use. The only billable unit. | | **Billed install** | Synonymous with cleared install on GHAN. Distinct elsewhere. | | **Excluded fraudulent install** | A claim rejected by one of the fourteen [rejection conditions](/research/desktop-install-network-safety-and-fraud/). Refunded automatically, exposed with a reason code. | Most disagreements about CPI are disagreements about which of these rows the price attaches to. ## Comparing a CPI rate to search spend 1. Take the search spend for a period. 2. Count the installs from that spend **that were still active 48 hours later** — not total installs. 3. Divide. That is your real cost per retained user. 4. Compare it to the rate card above, which is already a retained price. Step 2 is the one most teams have never run. It usually moves the number by a factor of two to four. Longer treatment: [GHAN vs Google Ads](/compare/google-ads/). ## Methodology for the observed report Once trading starts, this page gains a dated observed section generated from the ledger rather than written by hand: - **Sample period** — explicit start and end dates, never a rolling unlabelled window. - **Split** — by category band, by platform (macOS, Windows), by country, and by campaign volume decile. - **Reported per band** — median and interquartile range of effective cost per cleared install, the clearing rate, and the fraud exclusion rate. - **Exclusions** — every chain rejected by a fraud rule is excluded from the CPI figures and reported separately, so the two numbers cannot be traded off against each other. - **Minimum sample** — no band is published below 200 cleared installs in the period. A band under the threshold is shown as *insufficient sample*, not omitted. - **Reproducibility** — every figure recomputable by a partner from `get_ledger` output for their own share of it. **First publication:** the month the first chains clear. Progress: [status](/status/). Until then, the only real numbers on this page are GHAN's own published prices, and they are labelled as such. ## What are the best cost per install rates for desktop software? GHAN's published rates are EUR 12-18 per cleared install for utilities and consumer applications, EUR 20-30 for creator tools, and EUR 35-50 for prosumer and B2B tools. Those are fixed, identical on macOS and Windows, and charged only for installs that were deterministically attributed and still in use 48 hours later. A rate from a network that bills on the install event is not comparable to these numbers without adjusting for the share of installs that do not survive, which is commonly between half and three quarters. ## How does cost per install work for desktop software? An advertiser is charged a price each time their application is installed as a result of a placement. The two things that decide whether a CPI rate is good are what counts as an install and who sets the price. On GHAN an install counts only if a single-use signed token was redeemed, the receiving application countersigned the claim, and the application was still in use 48 hours later; the price comes from a published rate card rather than an auction. ## What is the difference between an install and a billed install? An install is software arriving on a machine. A billed install on GHAN is a cleared install - attributed by a valid single-use token, countersigned by the receiving app, and still in use at 48 hours. Every install that is not a cleared install costs the advertiser nothing and earns the serving app nothing. The gap between the two is the number that decides whether a CPI rate was a good price. ## Is CPI different on Windows and macOS? Not on GHAN. The rate card is keyed to the category of the application being installed, not to the operating system, so the same creator tool costs the same whether the install lands on macOS or Windows. Platform affects which gate check applies - a notarisation ticket on macOS, an Authenticode chain on Windows - not the price. ## How do I compare a CPI rate to my Google Ads spend? Divide your search spend by the installs that were still active 48 hours later, not by total installs, and compare that to the rate card. Most apps doing this for the first time find their real cost per retained user is two to four times their reported cost per install, because search reporting counts the click and the install rather than the survival. ## Where do these numbers come from? The rate card figures are GHAN's own published prices, fixed in code at packages/shared/ratecard.ts and served by the public get_rate_card tool - they are facts about what GHAN charges, not estimates of a market. Observed market figures are not published here because GHAN has not traded yet, and inventing them would contradict the product. The methodology for the observed report is below, with the date it first publishes. --- # GHAN reports URL: https://ghan.io/reports/ Updated: 2026-09-22 Reports are generated from the ledger and the fraud flag table rather than written by hand, which is why there are fewer of them than a marketing site would have and why the ones that exist say plainly where the data stops. ## Published - [Desktop software CPI benchmarks and rates](/reports/desktop-software-cpi-benchmarks/) — the published rate card, the definitions, a worked calculation, and the methodology for the observed figures. ## Scheduled - **Monthly public fraud report** — installs rejected by rule, euros clawed back, apps throttled, suspended and expelled. Generated from `fraud_flags` and the ledger. First publication: the month the first chains clear. - **Observed CPI by category and platform** — added to the benchmark report on the same schedule, with a 200-cleared-install minimum sample per band. See [transparency](/transparency/) for how any of it can be verified without GHAN's cooperation, and [status](/status/) for what exists today. ## How often are reports published? The fraud report is monthly and generated automatically from the fraud flag table and the ledger. The CPI benchmark report gains a dated observed section each month once trading starts. Network-wide figures are also available continuously and without an account through the public get_network_stats tool. --- # Desktop install safety and fraud — GHAN's standard URL: https://ghan.io/research/desktop-install-network-safety-and-fraud/ Updated: 2026-09-22 Bundling other applications inside your installer is not safe, and the reason is mechanical: antivirus vendors classify behaviour, and software arriving through an install flow nobody chose is the signature of unwanted software. ## The direct answer on installer bundling **No, it is not safe, and the reason is mechanical.** An installer is a sequence of screens whose purpose is to be clicked through. A third-party offer placed in that sequence is not competing for a considered decision; it is competing for a reflex. That makes every increment of ambiguity between "continue" and "accept" worth money, and ordinary A/B testing finds that ambiguity without anyone intending to deceive. Antivirus vendors do not evaluate intent. They classify behaviour, and software arriving through an install flow a person did not deliberately choose is the defining behaviour of a potentially unwanted program. The decisive detail is that the detection attaches to the **SDK**, not to an individual offer. So the developer who integrated carefully, explained every offer and pre-checked nothing gets the same detection as the worst actor in the network. That is why the category emptied rather than shrank. Full history: [why install networks die](/blog/why-install-networks-die/). ## GHAN's safety standard, in writing ### Consent - The SDK emits **no telemetry** while the host application reports consent as false. Data buffered before consent is discarded, not flushed. - A templated card may still render without consent, because rendering a card is not processing personal data. The host application can gate that too. - The host application is the controller; GHAN is the processor. Terms: [DPA](/dpa/). ### Disclosure - Placements are visibly a recommendation of another application, with the partner's name and icon. - A dismiss affordance is always present. - Nothing is pre-selected, because there is no selection control — there is a card and an Install button. ### Uninstall - Clicking Install opens the partner's own download URL. The person completes the partner's own installer, or does not. - GHAN never installs, modifies or removes software. - Removing a partner application has no effect on the host application, and uninstalling the host removes the SDK with it. ### Prohibited installer behaviour None of the following is permitted, and none of it is technically possible through the SDK: 1. Any placement inside an installer or uninstaller process. 2. Pre-checked or pre-selected offers of any kind. 3. Silent, background or automatic installation of any software. 4. Placements that imitate a system dialog, an error, or an update prompt. 5. Partner-supplied HTML, JavaScript, images beyond the icon, or any remote markup. 6. Modifying, wrapping or reimplementing the SDK's rendering or attribution behaviour. 7. Bundling a GHAN partner's binary into your own distribution. ## The definition of a cleared install > A **cleared install** is an install that was attributed by a valid, unexpired, single-use signed token, claimed by the receiving application with its own ed25519 signature, and still present and in use 48 hours after the claim. Pairs trading above EUR 500 per day with each other clear on **day-7 engagement** instead — a stricter bar applied exactly where the incentive to cheat is largest. Advertisers are billed for cleared installs and nothing else. Impressions and clicks are never billed. ## Every rejection and reversal condition | # | Condition | Stage | Reason code family | Effect | |---|---|---|---|---| | 1 | Token expired | Claim | `fraud_token_expired` | Reject, refund hold | | 2 | Token already used | Claim | `fraud_token_reused` | Reject, refund hold | | 3 | Token unsigned or signature invalid | Claim | `fraud_token_invalid` | Reject, refund hold | | 4 | Receiving signature missing | Claim | `fraud_unsigned_claim` | Reject, chain cannot advance | | 5 | Virtual machine or hypervisor indicator | Claim | `fraud_vm_detected` | Reject, refund hold | | 6 | Operating system installed under 48 hours ago | Claim | `fraud_fresh_os` | Reject, refund hold | | 7 | Hardware hash already seen on another claim | Claim | `fraud_duplicate_device` | Reject; 3+ from one partner throttles that partner | | 8 | Claiming IP's autonomous system is a hosting provider | Claim | `fraud_datacenter_asn` | Reject, refund hold | | 9 | Click-to-install time in an anomalous band | Post-claim | `fraud_ctit_anomaly` | Reject the band, flag the source | | 10 | Not present or not in use at the 48-hour check | Clearing | `not_retained` | No clearing, refund hold | | 11 | Cohort retention curve unlike the category baseline | Clearing | `fraud_retention_shape` | Hold clearing, manual review | | 12 | Canary probe unanswered by the shipped build | Continuous | `fraud_canary_fail` | Suspend app, freeze escrow | | 13 | Net flow between a pair exceeds its cap | Continuous | `pair_cap_exceeded` | Stop clearing for that pair | | 14 | Circular flow across three or more apps | Monthly | `fraud_collusion_graph` | Suspend, clawback | Conditions 1–10 resolve automatically. 11–14 are reversible by an administrator. Every one is visible to the affected app through `get_stats` with its reason code — transparency applies to the installs you were **not** paid for, which is the half that usually stays hidden. A reversal after clearing is recorded as a **new ledger line** (`clawback`). The ledger blocks `UPDATE`, `DELETE` and `TRUNCATE` at the database level, so nothing is ever edited away. ## Why the economics matter more than the rule list Rules alone lose, because a motivated attacker studies them. The structural defence is an inequality applied to every monetised feature before it is built: > The cost to fake an event must exceed the payout for it. Faking one cleared install requires forging an ed25519 signature belonging to an SDK inside another company's signed binary, on a machine that does not look virtualised, from an IP that is not a hosting provider, with a plausible click-to-install time, that is then used again two days later, inside a pair whose net flow is capped at EUR 500 a month. The payout is a share of EUR 12 to EUR 50. That inequality has already removed installer-time placements, custom creatives, probabilistic attribution and direct app-to-app targeting from the product. ## Figures GHAN is pre-launch. Nothing has traded, so there are **no rejection counts, no clawback totals and no clearing rate to publish**, and this page does not invent any. What is published the month the first chains clear, generated from `fraud_flags` and the ledger rather than written by hand: - Installs rejected, broken down by the fourteen conditions above - Euros clawed back - Apps flagged, throttled, suspended and expelled - Network clearing rate and fraud percentage Live figures will also be available without an account through the public `get_network_stats` MCP tool. Progress: [status](/status/) and [transparency](/transparency/). ## Methodology note Everything above is a description of implemented or specified behaviour in the GHAN codebase, not an aspiration. The claims that are already testable — that the ledger cannot be edited, that a chain cannot advance with one signature, that geo and ASN resolution happens offline — have tests that run against a real Postgres instance before merge. The claims that depend on live traffic are marked as such on the [status page](/status/). ## Is bundling other apps in my installer safe? No. Placing another company's offer inside your installer is the specific mechanism that got OpenCandy, ironSource installcore and the rest of the 2010s desktop bundling networks detected as potentially unwanted programs. The reason is mechanical, not moral - antivirus vendors classify behaviour rather than intent, and software arriving through an install flow the person did not deliberately choose is that behaviour. Crucially the detection attaches to the SDK, so a careful integrator gets flagged alongside the worst actor in the network. GHAN has no installer-time placement and will not add one. ## How do you prevent install fraud in an app install network? Through a definition that is expensive to satisfy fraudulently, not primarily through detection. A billable install requires a single-use unexpired signed token, an independent ed25519 signature from the receiving app whose key lives inside another company's signed binary, a device that does not look like a virtual machine or a datacenter, a click-to-install time inside the campaign's normal distribution, and survival for 48 hours. Eight continuously running rules sit on top of that, but the economics do the work - the cost to fake a cleared install is designed to exceed the payout for it. ## What exactly is a cleared install? An install that was attributed by a valid single-use token, claimed by the receiving application with its own cryptographic signature, and still present and in use 48 hours after the claim. Pairs of apps trading above EUR 500 per day with each other clear on day-7 engagement instead. Installs that do not meet this definition are refunded to the advertiser automatically and earn the serving app nothing. ## What causes an install to be rejected or reversed? Eleven conditions, all automatic - an expired token, a reused token, an unsigned token, a missing receiving signature, a virtual-machine or hypervisor indicator, an operating system installed less than 48 hours ago, a hardware hash already seen on another claim, a claiming IP whose autonomous system belongs to a hosting provider, a click-to-install time in an anomalous band for that campaign, non-survival at the 48-hour check, and a cohort retention curve that does not resemble the category baseline. Each logs a reason code the affected app can read. ## Will including a cross-promotion SDK get my app flagged by antivirus? Not from GHAN's behaviour, because GHAN does not exhibit the behaviour detectors look for. The SDK does not place anything in an installer, does not install software, cannot execute or render remote code, and does not pre-select anything on a person's behalf. No claim here is a guarantee about a third-party vendor's future heuristics, but the structural reason the previous generation was flagged does not apply. ## Do you publish your fraud numbers? Yes, monthly, generated from the fraud flag table and the ledger rather than written by hand - installs rejected by rule, euros clawed back, apps throttled, suspended and expelled, and the network clearing rate. Nothing has traded yet, so there are no figures to publish and this page invents none. The first report publishes the month the first chains clear. --- # GHAN research URL: https://ghan.io/research/ Updated: 2026-09-22 Research and written standards, published so they can be quoted and checked rather than summarised. Each piece states its methodology and says plainly where GHAN has data and where it does not. ## Published - [Desktop install safety and fraud — GHAN's standard](/research/desktop-install-network-safety-and-fraud/) — is installer bundling safe, the prohibited-behaviour list, the definition of a cleared install, and all fourteen rejection and reversal conditions. - [Desktop software CPI benchmarks](/reports/desktop-software-cpi-benchmarks/) — what cost per install means for desktop software, GHAN's published rates by category and platform, and the methodology for the observed figures that follow. ## Standing methodology 1. **No figure is published that cannot be regenerated** from the ledger or the fraud flag table. 2. **Absence is stated, not estimated.** Where GHAN has no data, the page says so and gives the date the data will exist. 3. **Definitions come before numbers**, because most disagreements about install metrics are disagreements about what counts as an install. 4. **Every published aggregate has a per-app view** that the affected partner can check against signatures it produced itself. See [transparency](/transparency/). ## Does GHAN publish original data? It will, generated from the fraud flag table and the ledger rather than written by hand, the month the first chains clear. Until then the research here is definitional and methodological - the safety standard, the rejection conditions, the published rate card - and it says explicitly where a figure does not exist yet rather than estimating one. --- # The nine security layers URL: https://ghan.io/security/ Updated: 2026-09-22 GHAN has nine independent layers between a member application and a harmful or fraudulent install. Any one of them failing does not open the network, because they defend different things. This page lists all nine, says which are live today, and states plainly what the SDK cannot do. ## The nine layers They are listed in the order a bad actor would meet them. Each defends something the others do not, which is the point of having nine rather than one good one. | # | Layer | What it stops | Status | |---|---|---|---| | 1 | **Gate** | An unsigned, malicious or disposable app entering the network at all | Specified; VirusTotal and RDAP wired | | 2 | **Placement** | A partner reaching your users with anything but a templated card | Specified in the SDK contract | | 3 | **Attribution** | Installs being credited that cannot prove where they came from | Signing and canonical JSON live and tested | | 4 | **Device** | Install farms, virtual machines, datacenter claims | Offline ASN and datacenter detection live | | 5 | **Economics** | Fraud that survives every technical check but is unprofitable anyway | Ledger and escrow schema live | | 6 | **Behaviour** | Apps that look clean per-chain but wrong in aggregate | Specified | | 7 | **Enforcement** | A detected problem continuing to cost partners money | Specified; kill switch in the SDK contract | | 8 | **Data** | The record of what happened being edited after the fact | **Live and proven on a real database** | | 9 | **Disclosure** | Any of the above quietly not being applied | Live — this page, and the reason codes | "Specified" means designed and written down, not yet running against live traffic, because GHAN has not traded. The [status page](/status/) is the authoritative list of what exists today. --- ### Layer 1 — The gate Five automated checks, run at registration and **re-run every week**, because an app that was clean when it joined is not clean forever. 1. A notarised macOS build, or a valid Windows Authenticode chain. 2. A clean [VirusTotal](https://www.virustotal.com/) result — no malicious or suspicious detections above threshold. 3. A domain at least six months old, verified over RDAP. It is the cheapest check a disposable operation cannot pass, because the one thing it is trying to save is time. 4. A contact email that answers a challenge. 5. A download URL that actually serves the bundle identifier the app declared. Failures return machine-readable reason codes, not prose. Detail: [vetting and scoring](/vetting/). ### Layer 2 — The placement layer What the SDK renders is fixed: partner icon, partner name, one generated line, an install button, a dismiss affordance. That is the complete set. Five properties, stated as implementation facts so they can be checked rather than believed: 1. **Cannot render remote markup.** The placement payload has no field for HTML, JavaScript or a script URL. 2. **Cannot install anything.** The SDK opens a URL. The person completes the other app's installer, or does not. 3. **Cannot show a card you did not request.** Nothing renders unless your code calls `ghan.slot()`. 4. **Cannot bypass your consent state.** Telemetry is gated on a value your application passes in. 5. **Cannot appear inside an installer.** There is no installer-time slot, and adding one is ruled out by [Commandment III](/manifesto/). Plus your own controls, enforced client-side in your build: category and named-app exclusions, and a frequency cap. GHAN cannot override them from the server because there is no server field that does. ### Layer 3 — Attribution A single-use, 15-minute, ed25519-signed token, countersigned by the receiving application's own key. Single use is a unique database constraint rather than an `if` statement, because an `if` statement has a race condition. Two independent signatures are required before a chain can advance past the claim. Neither party can produce the other's; neither can GHAN. No fingerprinting, no probabilistic matching, no fallback. Detail: [deterministic attribution](/attribution/). ### Layer 4 — Device signals Attached to every install claim: virtual-machine and hypervisor indicators, operating-system install age, a **salted** hardware hash — never the raw identifier — and clock skew. The claiming IP's country and autonomous system are resolved from an **offline** database, so no partner IP address is sent to a third party on the hot path. A desktop install claim arriving from a hosting provider's AS is an install farm, and that is a stronger signal than city-level geography. These signals exist to kill fraudulent chains, not to identify people, and they are deliberately worse at identifying people than the fingerprinting GHAN refuses to perform. ### Layer 5 — Economics The layer that does the most work, because rules alone lose to a motivated attacker who studies them. Every monetised feature has to satisfy one inequality before it ships: > The cost to fake an event must exceed the payout for it. Faking one cleared install means forging an ed25519 signature belonging to an SDK inside another company's signed binary, on a machine that does not look virtualised, from an IP that is not a hosting provider, with a plausible click-to-install time, that is then used again two days later, inside a pair whose net flow is capped at EUR 500 a month. The payout is a share of EUR 12 to EUR 50. That inequality has already removed installer-time placements, custom creatives, probabilistic attribution and direct app-to-app targeting from the product. ### Layer 6 — Behaviour Per-chain checks can be passed. Aggregates are much harder to fake. - **Cohort retention shape** compared against the category baseline. A suspiciously perfect curve holds clearing, as does a cliff. - **Canary probes** — the server sends signed liveness requests and the SDK answers with its own signature, proving a slot is genuinely live in a shipped build rather than merely declared in a dashboard. - **Complaint rate**, tracked per app, feeding the behaviour score. ### Layer 7 — Enforcement | Step | Trigger | Effect | |---|---|---| | Flag | Any rule fires | Logged, visible in `get_stats` | | Hold clearing | Retention shape, geo anomaly | Chains stop clearing, escrow stays held | | Throttle | Repeated device rejects, low behaviour score | Placement volume cut | | Suspend + freeze | Canary failure, token forgery, confirmed collusion | All placements off, escrow frozen | Plus the **kill switch**: the server disables every placement for an app instantly, honoured on the next fetch, no release required. It exists for the day you need to answer a reviewer in minutes rather than in a release cycle. Every action is reversible by an administrator and visible to the app it happened to. There is no silent throttle. ### Layer 8 — Data The only layer that is fully live and proven today. - `UPDATE`, `DELETE` and `TRUNCATE` on the `ledger` table are **blocked by database trigger**, with a test that proves all three fail against a real Postgres instance before merge. Corrections are new lines. - Row-level security on every table; the public API roles revoked. - TLS verified against a **pinned root certificate**, not with verification disabled. - Private signing keys generated on end-user devices and never transmitted. - Secrets in environment variables only; nothing in source control. - Every fraud rule and every ledger mutation has a test that runs before merge. ### Layer 9 — Disclosure A control nobody can see is a control nobody can rely on. - All fourteen [rejection and reversal conditions](/research/desktop-install-network-safety-and-fraud/) published, each with a stable reason code. - `get_stats` returns `fraud_rejected` broken down by reason code — transparency applies to the installs you were **not** paid for. - A monthly public fraud report generated from the flag table and the ledger, not written by hand. - `get_network_stats` public and unauthenticated, so the clearing rate and fraud percentage need no account to read. --- ## What the SDK collects **Behavioural counters, only after consent:** session start and end, coarse feature counts defined by the host application, whether a card was dismissed. **Fraud signals, at install claim:** VM and hypervisor indicators, OS install age, a salted hardware hash, clock skew, and the claiming IP's country and ASN resolved offline. **Never, under any circumstances:** file names, file contents, paths, window titles, clipboard contents, keystrokes, screen contents, raw hardware identifiers, MAC addresses, serial numbers, email addresses, advertising identifiers, cross-application identity, browsing history, or anything at all outside the host application. GHAN's attribution is deterministic precisely so that it does not need identity. A network that refuses fingerprinting does not need a fingerprint. ## Consent and GDPR The SDK's consent-safe mode emits nothing before the host app reports consent as true, and telemetry buffered before consent is **discarded rather than flushed**. A templated card can still render without consent, because rendering a card is not processing personal data — but you can gate that too. You are the controller; GHAN is the processor. See [privacy](/privacy/) and the [DPA](/dpa/). ## The answer for a reviewer If somebody asks whether you shipped adware, this is the checkable version: > The app includes the GHAN SDK, which shows an occasional card recommending another notarised, malware-scanned desktop application, at moments the app itself chooses, after installation and never inside an installer. Nothing is pre-checked and nothing installs without the person completing the other app's own installer. The SDK cannot render remote code, collects behavioural counters only, emits nothing before consent, and can be turned off entirely from the server. Every sentence in that paragraph corresponds to something on this page that a reviewer can verify from the SDK source or from a packet capture. That is the only kind of security claim worth making. ## Is GHAN adware? No. Adware installs or displays software the person did not ask for, usually by bundling it into an installer with a pre-checked box. GHAN never touches an installer, never pre-selects anything, and nothing is installed unless the person clicks a card and then completes the other application's own installer themselves. Every app that can appear in a card has passed a notarisation or Authenticode check and a malware scan first, re-run weekly. ## Can GHAN push code into my application? No. The SDK arrives as a dependency in a build you compile and sign yourself. At runtime it fetches a signed placement payload consisting of an app id, an icon URL, a name and one line of text - there is no field in that payload that carries markup or code, and no code path in the SDK that would execute one if there were. The only thing the server can push is the kill switch, which turns placements off. ## What are the security layers? Nine. The gate (code signature, malware scan, domain age, contact challenge, binary identity). The placement layer (templated only, no installer, host-controlled). Attribution (single-use signed tokens, double signing). Device signals (VM, OS age, salted hardware hash, clock skew, datacenter ASN). Economics (48-hour clearing, escrow, pair caps, cost-to-fake above payout). Behaviour (cohort retention shape, canary probes, complaint rate). Enforcement (flag, hold, throttle, suspend, kill switch, clawback). Data (append-only ledger, row-level security, pinned TLS, no PII). Disclosure (published rules, reason codes, monthly fraud report). ## Where is the signing key stored? In your application's own data directory on the end user's machine, generated on first run. The private key never leaves that machine and GHAN never receives it. Only the public key is registered, during the activation handshake. ## Is GHAN GDPR compliant? The SDK ships a consent-safe mode in which the host application passes its own consent state and no telemetry is emitted until it is true. The data collected is behavioural counters and fraud signals rather than personal data, GHAN publishes what those fields are, and a data processing agreement is at /dpa/. As always, compliance depends on your own implementation and disclosure as the controller. ## What does GHAN do if a member app turns malicious? It loses its gate pass at the next weekly re-run and stops trading. The kill switch disables its placements network-wide within one fetch cycle, escrow is frozen, and the event appears in the monthly public fraud report. The weekly re-run of the malware and signature checks exists precisely because an app that was clean at registration is not clean forever. ## What data does the SDK collect? Behavioural counters after consent - session starts and ends, coarse feature counts, card dismissals - and fraud signals attached to an install claim, which are VM indicators, OS install age, a salted hardware hash and clock skew. Never file contents, window titles, clipboard, keystrokes, raw hardware identifiers, or anything personally identifying. --- # GHAN network status URL: https://ghan.io/status/ Updated: 2026-09-22 GHAN is pre-launch and in its founding-partner phase. The referee core is built and tested against a real database; money and the SDK are in progress. There are no network statistics on this page because nothing has traded yet, and inventing them would contradict the entire product. ## What is built | Component | State | Evidence | |---|---|---| | Database schema, all core tables | Live | Migrations applied to a real Postgres instance | | Append-only ledger | Live | A test proves `UPDATE`, `DELETE` and `TRUNCATE` all fail | | Row-level security, public API roles revoked | Live | Migration plus test | | ed25519 signing and canonical JSON | Built | Unit tested | | Rate card as code | Built | `packages/shared/ratecard.ts`, published via `get_rate_card` | | Offline geo and datacenter detection | Built | ASN lookups on the hot path, no partner IP leaves the infrastructure | | Payment rails, sandbox | Wired | Stripe Connect Express, test mode | ## What is in progress - Token issue and claim, end to end - The event-chain state machine and the escrow ledger flow - The vetting gate: notarisation and Authenticode, malware scanning, RDAP domain age, email challenge - The `@ghan/sdk` package for Electron, Tauri and Node - The public MCP server and its registry listings ## What has not started - Native Swift and Windows C# SDKs - The read-only dashboard - x402 machine payments in production - Any trading at all ## What this page will show once trading starts The same figures `get_network_stats` returns, refreshed automatically: - Average CPI by category - Clearing rate across the network - Fraud rejection percentage - Installs rejected by rule, monthly - Euros clawed back, monthly - Apps throttled, suspended and expelled, monthly Until then this page says what it says. See [transparency](/transparency/) for how those numbers will be verifiable, and the [changelog](/changelog/) for what shipped when. ## Is GHAN live? Not for general trading. The referee core - signing, tokens, the event-chain state machine and the append-only ledger - is built and tested against a real Postgres database. The SDK, the money rails and the public MCP server are in progress. Founding partners are being onboarded now. ## Why are there no network statistics? Because nothing has traded, so any number would be fabricated. A network whose positioning is that a partner's agent can audit it cannot open with invented figures, and the absence of numbers here is the first test of whether that claim is real. ## When will the first transparency report be published? The month the first chains clear. It is generated from the fraud flag table and the ledger rather than written by hand, so it will exist as soon as there is anything in those tables. ## Can I join now? Yes, as a founding partner. Your app has to pass the same gate as everyone else, which includes the six-month domain age requirement. Email hello@ghan.io or register through the MCP server. --- # GHAN terms of service URL: https://ghan.io/terms/ Updated: 2026-09-22 Membership requires passing and continuing to pass the vetting gate. Advertisers are billed only for cleared installs. Fraud enforcement is automated, laddered and reversible, and every action taken against an account is visible to that account. **Effective 22 September 2026.** By registering an application you agree to these terms. ## 1. Eligibility You must be able to enter a binding contract, and the application you register must be a desktop application for macOS or Windows that you are authorised to distribute. You must pass the [vetting gate](/vetting/) and continue to pass it at each weekly re-run. ## 2. The gate is a continuing condition Gate checks are re-run weekly. An application that loses its code-signing validity, begins triggering malware detections, or ceases to serve the bundle identifier it declared stops trading until it passes again. This is not a penalty; it is the condition of membership. ## 3. Placements - The GHAN SDK renders only templated cards. You may not modify, wrap or reimplement the rendering. - You may not place GHAN content inside an installer, and the SDK provides no mechanism to do so. - You choose which lifecycle slots are enabled and your own frequency cap. - GHAN may disable your placements instantly via the kill switch where a security or integrity issue requires it. ## 4. Billing and clearing - Advertisers are billed per **cleared install** at the [published rate card](/pricing/). - Credits are held in escrow from install claim and released only at clearing. - Chains that do not clear are refunded automatically. No dispute process is required, because none should be. - GHAN retains 30 percent of each cleared install. Serving apps earn 70 percent, or 84 percent of CPI in value taken as credits. ## 5. Fraud and enforcement Automated rules may flag, hold clearing, throttle, or suspend an account and freeze escrow. Every action is logged with the rule that triggered it and is visible to the affected account through `get_stats`. Every action is reversible by an administrator. Clawbacks for chains later found fraudulent are recorded as new ledger lines. Nothing is ever edited or deleted. ## 6. Payouts Through Stripe Connect Express, monthly, minimum EUR 50. Identity verification is required where the volume or the jurisdiction demands it. Zero-history accounts buying above a threshold post a refundable EUR 250 deposit, returned after 1000 cleared installs with clean retention. ## 7. Prohibited conduct - Forging, replaying, harvesting or reselling attribution tokens - Claiming installs from virtual machines, emulators or datacenter infrastructure - Colluding with another member to generate installs whose purpose is payout extraction - Misrepresenting placement inventory, including failing to answer canary probes while claiming to serve - Modifying the SDK's rendering or attribution behaviour - Distributing malware, adware, or software that misrepresents what it does ## 8. Suspension and termination You may leave at any time: disable placements, request a payout of any balance above EUR 50, and ship your next release without the SDK. GHAN may suspend an account for a breach of section 7 or a sustained gate failure, and may terminate for a repeated or severe breach. Cleared earnings remain payable subject to clawback. ## 9. Liability GHAN provides the network as described. GHAN is not liable for the conduct of member applications beyond the vetting and enforcement described here, nor for indirect or consequential loss. Nothing here excludes liability that cannot lawfully be excluded. ## 10. Changes Material changes are announced in the [changelog](/changelog/) and [RSS feed](/feed.xml) before they take effect. Campaigns running at the time of a rate-card change continue at the prior rate until the end of the billing period. ## Can GHAN suspend my app without telling me? No. Every automated action - flag, hold clearing, throttle, suspend - is visible through get_stats with the rule that triggered it. There is no silent throttle, because a network that quietly reduces your volume while continuing to report normally would be indistinguishable from one that is failing. ## What happens to my balance if I am suspended? Cleared earnings remain payable and can be withdrawn once the account's status permits, subject to any clawback for chains later found fraudulent. Escrow held against unresolved chains is frozen until those chains resolve or expire. Suspension is reversible by an administrator. ## Can the rate card change? Yes, as a versioned change announced in the changelog and its RSS feed before it takes effect. Campaigns running at the time of a change continue at the rate in effect when they were created until the end of the billing period. --- # GHAN transparency report URL: https://ghan.io/transparency/ Updated: 2026-09-22 GHAN publishes a monthly fraud report generated from its own flag table and ledger, plus live network statistics through a public unauthenticated MCP tool. The point is not the numbers being good; it is that a partner's agent can recompute them without GHAN's cooperation. ## What gets published, and where | Figure | Where | Frequency | |---|---|---| | Average CPI by category | `get_network_stats`, [status](/status/) | Live | | Clearing rate | `get_network_stats` | Live | | Fraud percentage | `get_network_stats` | Live | | Installs rejected by rule | Monthly fraud report | Monthly | | Euros clawed back | Monthly fraud report | Monthly | | Apps throttled, suspended, expelled | Monthly fraud report | Monthly | | Your own everything | `get_stats`, `get_ledger` | Live | `get_rate_card` and `get_network_stats` are public and unauthenticated. You do not need an account to audit GHAN's public claims. ## How to verify a charge yourself 1. Pull your ledger: `get_ledger { app_id, from, to }`. 2. Take any line and read its `event_chain_id`. 3. Pull the chain. It contains the impression, the click, the token id and its expiry, the install claim, both signatures, the device signals, the activation or rejection, and the escrow hold and its release. 4. Verify `sig_receiving` against your own registered public key. That signature was produced by an SDK inside a binary you compiled and signed. 5. Recompute the total. It is arithmetic over lines you can now independently verify. Step 4 is the one that matters. GHAN cannot manufacture a billable install without a signature it does not have. ## Why the ledger is append-only `UPDATE`, `DELETE` and `TRUNCATE` on the `ledger` table are blocked by a database trigger, and the migration that installs the trigger has a test that proves all three fail against a real Postgres instance. A correction is therefore always a new line — a clawback, an adjustment, a reversal — visible to both parties with its own timestamp. The history of a disagreement is preserved rather than resolved into a single final number. ## The standing commitment Every milestone GHAN ships is accepted against the same rule: > A partner's agent must be able to verify the milestone's claims from `get_ledger` and `get_stats` output alone. If a claim cannot be checked that way, it does not go on this website. ## Current state GHAN is pre-launch. The referee core — signing, tokens, the event-chain state machine, the escrow ledger flow — is built and tested against a real Postgres database, including tests that prove a chain cannot advance with one signature and that the ledger cannot be edited. There are no network statistics yet because nothing has traded yet, and this site publishes no invented ones. See [status](/status/) for what is built, what is in progress and what is not started. ## What exactly does GHAN publish? Monthly - installs rejected broken down by fraud rule, euros clawed back, apps throttled, suspended and expelled, the network clearing rate, and average CPI by category. Continuously, through the public get_network_stats MCP tool - average CPI per category, clearing rate and fraud percentage. Per app, through get_stats and get_ledger - your own impressions, clicks, installs, cleared installs, retention and fraud rejections with reason codes. ## Can I verify the published numbers myself? For everything you took part in, yes, completely. Every ledger line carries an event chain reference, every monetised chain carries two independent signatures, and one of those signatures was produced by an SDK inside your own signed binary. You can recompute your own totals from data you already hold and compare. For network-wide aggregates you are trusting the aggregation, which is why the underlying per-app data is exposed rather than only the summary. ## Why publish fraud numbers at all? Because a network that publishes no fraud number is not a network with no fraud - it is a network you cannot evaluate. Publishing rejections also removes the incentive to quietly bill for chains that should have been refunded, since the rejection rate and the clearing rate are the same number seen from two sides. ## Are there network statistics today? Not yet. GHAN is in its founding-partner phase and no trades have cleared, so there are no install counts to publish and this site does not invent any. The status page states what is built and what is not, and the first transparency report is published the month the first chains clear. --- # How GHAN vets and scores apps URL: https://ghan.io/vetting/ Updated: 2026-09-22 No app can trade on GHAN until it passes an automated gate covering code signing, malware scanning, domain age, contact verification and binary identity. After that a reputation score ranks it, and once it has traded 500 installs its measured behaviour replaces reputation entirely. ## Layer 1 — the gate Pass or fail, fully automated, run on registration and again every week. | Check | What is verified | Source | |---|---|---| | Code signature | macOS notarisation ticket, or a valid Windows Authenticode chain | Apple notarisation API / signature inspection | | Malware | No malicious or suspicious engine detections above threshold | VirusTotal | | Domain age | At least six months since registration | RDAP | | Contact | A challenge message to the declared address is answered | Email challenge | | Binary identity | The download URL serves the bundle id the app declared | Direct fetch | Failures return as reason codes through `get_score`, not as prose in an email. A founder's agent can read the failure, fix what is fixable, and re-trigger. ## Layer 2 — reputation, 0 to 100 Reputation is what GHAN knows about an app before it has traded anything. | Component | Weight | What it measures | |---|---|---| | AI visibility and sentiment | 50% | Share of voice against the app's real category rivals in AI answers, and how those answers characterise it | | Release cadence | 20% | Time since the most recent release, from a GitHub release feed or a Sparkle appcast | | Reviews and video coverage | 20% | A floor check on independent reviews and video coverage existing at all | | Domain and social coherence | 10% | Whether the domain, the app name and the public profiles describe the same product | AI visibility carries half the weight because for a desktop app in 2026, being absent from every AI answer in your own category is a real signal: it means neither users nor the models answering their questions know you exist. Measuring it as share of voice against actual rivals, rather than as a raw mention count, makes the number comparable across categories of very different sizes. Release cadence matters because an app that has not shipped in a year is a support burden for whoever promotes it, independent of how good it is. Scores are cached for seven days. ## Layer 3 — behaviour After 500 installs traded, measured behaviour **replaces** reputation entirely. Nothing an app says about itself outranks what it has actually done. - 48-hour retention of installs it referred - Uninstall rate of those installs - Canary compliance — does the shipped build answer signed liveness probes - Complaint rate Below threshold, an app is auto-throttled. Canary failure suspends it and freezes escrow. ## Reading your own score ``` get_score { app_id: "app_..." } ``` Returns the status, the gate as a set of booleans, the reputation breakdown by component, the behaviour block once it exists, and the next review date. Every rejection reason is a code, not a sentence, so an agent can act on it without parsing English. ## Why the gate is public Publishing the gate makes it gameable in exactly one way: by satisfying it. Signing your binary, keeping it clean, owning your domain for six months, answering your email, and shipping the build you said you would ship are not loopholes. They are the product. ## What are the gate requirements? Five checks, all automated. A notarised macOS build or a valid Windows Authenticode chain. A VirusTotal result with no malicious or suspicious detections above threshold. A domain at least six months old, verified over RDAP. A contact email that answers a challenge message. And a download URL that actually serves the bundle identifier the app declared. Any failure rejects the application with a machine-readable reason. ## Why does domain age matter? Because it is the cheapest check that a disposable operation cannot pass. Registering a domain costs almost nothing, but waiting six months costs an attacker the one thing they are trying to save. It is a weak signal about quality and a strong signal about intent, which is exactly what a gate needs. ## How is the reputation score calculated? Reputation is a 0-100 weighted score - AI visibility and sentiment at 50 percent, release cadence at 20 percent, reviews and video coverage at 20 percent, and domain and social coherence at 10 percent. AI visibility is measured as share of voice against the app's actual category rivals rather than as an isolated number, so the score answers the question a partner actually has, which is whether this app is one that the models answering their users' questions already know about. ## What happens if my app fails the gate? You get a machine-readable list of exactly which checks failed and, where applicable, when they would pass. A domain that is four months old returns the date it becomes eligible. The gate re-runs automatically and nothing needs to be resubmitted by hand. ## Is the gate re-run after I am accepted? Yes, weekly. An app that lets its code-signing certificate lapse, or whose binary starts triggering malware detections, loses its gate pass and stops trading until it passes again. The gate is a continuous condition of membership, not an entry ritual. ---