DEV Community

Pritom Mazumdar
Pritom Mazumdar

Posted on

I built an open-source ad server for AI chat apps that keeps the chat on your server

Every message in a free AI app costs the person running it money. Most users will never pay for a subscription, so ads are the obvious way to cover the bill. ChatGPT started showing ads on its free tier this year.

If you run your own AI app and want ads today, the options are not great:

  1. Join an AI ad network. It works, but the network usually needs to see the user's conversation to pick an ad, and it keeps a cut of the revenue.
  2. Build your own ad system. Matching, budgets, click tracking, fraud checks, reporting. That is weeks of work next to your actual product.
  3. Hardcode a sponsor banner. Same ad for everyone, whatever they asked. It performs badly.

So I built Aside, an open-source ad server for AI chat apps that you run on your own server, next to your app. The conversation never leaves your infrastructure.

What it looks like

The demo is a fictional free cooking assistant called Rasoi AI. You can try it here: aside-ads.onrender.com

  • Ask "Paneer butter masala for 4 people?" and you get the recipe, with a card beside it labeled Sponsored: get the ingredients delivered in 10 minutes.
  • Ask "My kadhai keeps sticking, how do I fix it?" and the card is for cast-iron cookware instead.
  • Ask "Who invented the pressure cooker?" and there is no ad at all, because nothing is relevant enough.

The ad sits beside the answer. It is never mixed into the model's reply.

How it works

Matching runs locally. Aside embeds the user's latest message with a small local model (bge-small-en-v1.5 through fastembed, on CPU) and compares it with each campaign's targeting text. Nothing is sent to a third party.

No ad beats an irrelevant ad. There is a relevance threshold (0.65 by default). Below it, Aside returns nothing, and the response tells you why (below_relevance_threshold), which makes tuning easy.

Sensitive conversations get no ads. A guard checks for topics like self-harm, medical emergencies, grief and financial distress, and blocks ads there by default. The demo also keeps the next few turns ad-free after a sensitive message.

An auction picks the winner. Campaigns bid per click or per thousand views. Bid times relevance ranks them, and the winner pays a second price.

Budgets are enforced in the database. Daily and total budgets, even pacing across the day, and frequency caps per user. Budget is reserved when an ad is chosen, not when it is shown, so bursts cannot overspend. In a test with 60 simultaneous requests against a budget of 10 views, it served exactly 10.

Tracking can't be forged. Impression and click links are HMAC-signed and expire. Clicks and conversions are deduplicated, so a retried conversion postback counts once.

No chat text is stored. Only ad ids, hashed user ids and timestamps. There is a test that fails if conversation text ever reaches the database.

Using it

pip install aside-ads
aside seed-demo --scenario cooking   # sample sponsors, in INR
ASIDE_CURRENCY=INR aside serve       # ad server + dashboard on :8000
Enter fullscreen mode Exit fullscreen mode

From your app (Python or TypeScript):

from aside_ads_client import AsideClient

aside = AsideClient("http://localhost:8000", api_key)
ad = aside.get_sponsored(
    [{"role": "user", "content": user_message}],
    user_id=session_id,
    placement="chat-sidebar",
)
if ad:
    show_beside_answer(ad.headline, ad.body, ad.cta, ad.url)
Enter fullscreen mode Exit fullscreen mode
import { createClient } from "aside-ads";
Enter fullscreen mode Exit fullscreen mode

SQLite works out of the box. Postgres and Redis are optional for bigger setups. There is a small dashboard where you add sponsors, set bids and budgets, and see views, clicks and spend.

What it does not do

Aside does not bring advertisers. That is the real value of an ad network, and if you need that demand, a network is the right tool. Aside is for apps that sell sponsorships directly, run house ads for their own products, or simply cannot send user chats to someone else (health, finance, internal tools, or apps that need to stay on the right side of data protection rules).

Licence and links

This is version 0.1.0. I would love feedback on two things in particular: the default relevance threshold, and what a fair self-serve flow for small sponsors should look like. If you run an AI app and want to try it, I am happy to help set it up.

Top comments (0)