Slide 1

Slide 1 text

Creating a Free Video Ad Network on the Edge Mizoguchi Coji @techtalkjp Start Cloudflare x Hono x Remix

Slide 2

Slide 2 text

Motivation Solo media project: "Hyperlocal Tokyo" https://tokyo.hyper-local.app/ Use it to find good places to go right now Planning to continue for at least 10 years Eventually want to create and sell ad slots myself But existing services… Full of ugly ads Only cater to large-scale media Can’t create custom formats Even though I’m creating the media myself "Now, can I do it alone for free?" It’s almost a hobby. AI is available. Let’s create a video ad network from scratch Open source!

Slide 3

Slide 3 text

Demo 1. Ad server and JS SDK Video ad playback Audio ad playback Tracking vast impression progress (0%, 25%, 50%, 75%, 100%) click 2. Management UI: For advertisers/publishers Multi-tenant authentication with Clerk Delivery settings Ad slot management Check delivery performance

Slide 4

Slide 4 text

Technologies Used Cloudflare R2: Video storage Workers: Ad server implementation (Hono) VAST 4.1: Video ad standard Workers: Management UI (Remix) UI: shadcn/ui Clerk: Authentication & multi-tenancy Turso: Edge distributed DB (distributed SQLite) Kysely shadcn/ui

Slide 5

Slide 5 text

Architecture

Slide 6

Slide 6 text

Features Zero cost Up to 5 million impressions / month Everything runs on the edge Everything is built with TypeScript maintaining everything alone Start small and minimal Rebuild if needed Multi-tenant support Advertisers Publishers

Slide 7

Slide 7 text

Interesting Points of Implementation Ad selection SQL that INNER JOINs vigorously 😂 // Fetch ads matching category, media type, and companion banner sizes await db .selectFrom('ads') .innerJoin('companionBanners', 'companionBanners.adId', 'ads.id') .innerJoin('adGroups', 'adGroups.id', 'ads.adGroupId') .innerJoin('campaigns', 'campaigns.id', 'adGroups.campaignId') .innerJoin('advertisers', 'advertisers.id', 'campaigns.advertiserId') .where('campaigns.status', '==', 'ACTIVE') .where('ads.type', '==', mediaType) .where( 'companionBanners.width', 'in', companionSizes.map((s) => s.width), ) .select([ 'ads.id', 'ads.type', 'ads.url', 'ads.duration', 'ads.width', 'ads.height', 'ads.mimeType', 'ads.description',

Slide 8

Slide 8 text

Future Plans Implement common features like "even distribution" and "front-loading" for campaign budget management. Properly create the UI for ad submission It’s a bit tedious, but I’ll use comform. Need a dashboard and reports for the UI Waiting for the merge of DuckDB Wasm’s OPFS support by @eiichi292929. Please. Will maintain it steadily as OSS. It’s MIT licensed, so feel free to use it. If there’s demand, adding paid features could be interesting. Source code: github.com/coji/video-ad-network

Slide 9

Slide 9 text

Thank you https://github.com/coji/video-ad-network @techtalkjp