GHAN— by singular Get started

GHAN for desktop app developers

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 toYour earning per cleared install (cash)As credits
Utilities and consumerEUR 8.40–12.60EUR 10.08–15.12 of spend
Creator toolsEUR 14.00–21.00EUR 16.80–25.20 of spend
Prosumer and B2BEUR 24.50–35.00EUR 29.40–42.00 of spend

Those are 70 percent of the published rate card, 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

npm install @ghan/sdk
# or let your agent do it
npx @ghan/sdk init
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, 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 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 for the version you can hand to a reviewer.

Start

Read get started for the ten-minute path, or point your coding agent at the MCP server and let it register the app, read the score and open the integration PR itself.

Questions people ask about this

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.

Machine-readable versions of this page: markdown · llms.txt · llms-full.txt · OpenAPI · AI catalog