Tagly

Tagly

Tagly is a platform where local businesses pay their customers for posting about them on Instagram. Customers get rewarded based on the reach and audience fit of what they post and businesses get a new marketing channel without spending any time on it.

My role at Tagly

Co-Founder & Sole Engineer

Jan 2025 to Sep 2026

I co-founded Tagly and built the product on my own. We raised $100,000 and onboarded over 5,000 users. I built the three apps, the REST API and the seven workers behind them, a custom ledger, deposits and withdrawals through Stripe, and owned the deployment pipeline down to the App Store and Google Play reviews. Here are Tagly's biggest achievements:

  • 5,000+Users
  • 20+Paying businesses
  • Peaked at #1CZ App Store, Lifestyle
  • $100,000Raised
  • 2 appsLive on both stores

Why Tagly ended

We stopped Tagly in September 2026. We were only live in Prague and still onboarded over 5,000 users and more than 20 paying businesses. But the marketplace wasn't dense enough to become active. Reaching that density meant raising a pre-seed round, and investors wanted to see the marketplace active first. It's like Uber with only 20 drivers: people would sign up, but barely be able to use it.

What I've done here

Payments

Double-entry ledger

Designed the double-entry ledger behind every balance on Tagly. The ledger has 16 transaction kinds, covering deposits, withdrawals, refunds, payments, locks, unlocks, referral bonuses and adjustments. Customers, businesses and the platform each have an available and a reserved balance. Every movement of money is one row that can't be edited, and every row write goes through a single helper.

  • Stripe
  • PostgreSQL and PostGIS
  • Prisma

Three ways for a business to pay

Built the 3 ways a business can pay on Tagly: prepaid credits, pay-as-you-go, and automatic monthly top-ups. Credits are a one-off payment with no card kept on file. Pay-as-you-go charges a saved card whenever someone shares the business. Monthly top-ups refill the credit balance from the saved card at the start of each month. In the app, payments go through Stripe's native payment sheet. The sheet reporting success isn't proof the money moved, so the app only shows success once the backend has confirmed the payment.

  • Stripe
  • Express
  • React Native
  • Expo

Customer payouts to real bank accounts in Czechia and the US

Built the payouts that let customers withdraw their rewards straight to their own bank account, through Stripe Connect. Money moves from Tagly's platform balance to the customer's Stripe Connect account, then on to their bank. Every step shows up in the app. A reconciliation worker catches any payout stuck in an edge-case state.

  • Stripe

Stripe webhooks and reconciliation workers

Built the Stripe webhook handling that keeps Tagly's balances in sync with Stripe. The webhook handler covers 12 event types. Each event is recorded before Tagly acts on it, so nothing is ever counted twice. Reconciliation workers sweep for deposits that were never credited and withdrawals that got stuck, so no error state is left unresolved.

  • Stripe
  • Express
  • Node.js

Backend

Pricing each customer's post from 9 factors

Built the engine that decides how much a customer is paid for posting about a business. The engine prices each post from 9 factors. Three of the factors:

  • Geography: how far the customer's audience lives from the business, geocoded through AWS Location.
  • Authenticity: the account's size and its follower-to-following ratio. Smaller, more authentic accounts earn more than large ones.
  • Anti-spam: the more often someone posts, the lower each reward.

Every factor is stored on the reward, along with the version of the code that priced it. Any past payout can be recomputed exactly.

  • PostgreSQL and PostGIS
  • Kysely
  • Instagram Graph API
  • AWS

Anti-fraud checks for each share

Built the checks that stop Tagly from paying for a fake or repeated share. Every share has to pass AWS Rekognition, which reads the picture to confirm the right business was tagged. A cap in the pricing stops reshares from inflating a post's reach. A record of paid posts survives account deletion, so the same post can't be paid twice. Banned Instagram accounts are kept on a list, so a banned account can't be linked to a new Tagly account.

  • AWS
  • Instagram Graph API

Sign-in and per-account auth

Built sign-in and authentication across Tagly. Customers and businesses sign in with an email and a one-time code, or with Apple or Google. Customers can also sign in with Instagram, offered for anyone who's forgotten their email. One-time codes have attempt limits, resend limits and lockouts. After sign-in, every request carries a JWT with the caller's public uid. The uid's prefix is different for each account type, so the backend knows whether a customer, a business or an admin is calling. Each endpoint is only reachable by the account type it was built for.

  • Express
  • Resend
  • TypeScript

Full Instagram integration, approved by Meta

Built the Instagram integration that lets Tagly read statistics of the posts it pays for. The integration covers account connection, token refresh and permission handling, plus the data-deletion callbacks Meta requires before granting access in the Meta App Review. Two background workers collect the data. One pulls post-level insights for every share. The other takes a snapshot of the customer's account when they connect Instagram or create a share.

  • Instagram Graph API
  • Node.js

7 background services

Built the 7 background services that handle Tagly's work outside of API requests. All 7 run on ECS Fargate and share one framework. The services cover database maintenance, notifications, payments, Stripe reconciliation, cleanup, Instagram post insights collection and Instagram profile snapshot collection.

  • Node.js
  • AWS
  • Docker

52 notifications across push and email

Built the 52 notifications Tagly sends, across 11 categories: balance, shares, referrals, security, marketing and more. Each notification goes out as a push notification, an email, or both. Security and legal notices are mandatory. Every other notification can be turned off per channel. Marketing notifications that would land overnight wait until morning, and go out as a push first, with an email only if the push wasn't acted on. Marketing email also sends from a separate subdomain, so spam complaints can't stop an important notification from arriving.

  • Resend
  • Expo
  • Node.js

Hundreds of queries per screen, down to 2

Cut the cost of calculating the earnings estimate a customer sees on every business in the app, in two steps. Each business used to cost 11 database queries, run one after another, and 7 of those fetched the same customer data again every time. At its limit of 75 businesses, a full map screen would have cost around 825 queries. Moving the 7 customer-related queries out of the per-business loop, and running the rest in parallel, brought a full screen down to about 307. Then every estimate was cached in Redis per customer and per business, so loading a screen again costs 2 Redis reads. Counters on the customer and the business clear an estimate the moment anything that affects its price changes. If Redis is down, estimates fall back to live pricing.

  • Redis
  • PostgreSQL and PostGIS
  • Kysely

From a customer's Instagram story to a payout

Built the lifecycle every share on Tagly goes through, from a customer posting a story to Instagram to getting paid for it. An admin approves each share. 24 hours after the story goes up, a worker collects the post's data and a snapshot of the customer's profile. A share is only paid out once both steps are done. The price comes from the pricing engine, based on the collected data.

  • Instagram Graph API
  • PostgreSQL and PostGIS
  • Prisma

Rate limits on Redis

Built the rate limits that protect Tagly's REST API from abuse. There's one limit for signed-out traffic, one per logged-in account, and tighter limits on high-security endpoints like login. All the limits live in Redis, so each limit is shared across every server instead of counted per server.

  • Redis
  • Express

Fullstack

Three apps, two of them live on both stores

Built 3 React Native apps from scratch. The customer and business apps are live on the App Store and Google Play, and the internal admin dashboard is distributed through TestFlight. I handled the code, payments, deployment and infrastructure, as well as the App Store and Google Play reviews and listings. Tagly: Share and Earn peaked at number 1 in the Lifestyle category on the Czech App Store on 15 August 2026.

  • EAS Build and Submit
  • App Store Connect
  • Google Play Console
  • Instagram Graph API

Why Tagly couldn't ship as an MVP

For Tagly to work, we first had to pass Meta App Review, and passing it requires a full product, so Tagly couldn't ship as an MVP. Tagly also moved real money in both directions, which left no room for error. There's still a lot I decided against building:

  • Job queues live in Postgres instead of a separate queue service, so there's nothing extra to run or pay for in each environment.
  • The REST API and all 7 background services ship as one Docker image, told apart by a single environment variable.
  • An admin approves every share by hand before it's paid, rather than leaving it to automation alone.
  • The admin app stayed internal: iOS only, English only, installed through TestFlight. It updates together with the backend, so it needs none of the compatibility code the public apps carry.
  • PostgreSQL and PostGIS
  • Docker
  • App Store Connect

Two versions of the API live at once

Ran v1 and v2 of Tagly's REST API side by side, because an app already on someone's phone can't be updated on demand. Every request and response shape a shipped build relied on had to keep working, even as the database behind the API changed. A whole product area was deleted from the database while its old fields stayed supported for older builds. Only the API contract was versioned, so everything behind the contract could keep changing. Every piece of compatibility code carried a marker saying when it could be removed. Retiring v1 took three steps:

  • Built a minimum-version gate. Every request carries the app's version, and a build below the minimum is shown an update screen.
  • Raised the minimum version so every old install had to update, then waited out a safety window.
  • Deleted v1's endpoints, scanned for code that only v1 used, and dropped the database columns that only v1 wrote.

The whole cutover is written down as a repeatable procedure for the next version.

  • Express
  • TypeScript

All types are defined once, shared across the apps and the server

Built a shared package that defines every endpoint's request and response shape. Every app and service imports the same package, so the client and the server always agree on the shape of the data. The package holds 160 endpoint contracts. The backend validates every incoming request against these contracts, and the apps' SDK checks every response and logs any mismatch.

  • Zod
  • TypeScript
  • Express

English and Czech across the apps and the backend

Localised Tagly into English and Czech, from the apps to the backend's notification and email templates. Every user-facing string lives in a translation file, with English typed as the source, so a string missing from English is a type error. The language follows the device's language, and units follow the device's measurement system. Users can change both in their preferences.

  • i18next
  • React Native
  • TypeScript

Data

Fifty-table schema

Designed Tagly's whole database, from accounts to the ledger and the job queues. The database has 50 tables and runs on RDS. Job queues live in their own schema, apart from the money and account data that has to last. Prisma handles the schema and ordinary queries, and Kysely handles the queries an ORM can't express. A few of the design decisions:

  • Half-finished sign-ups live in separate pending tables. A real customer row only exists once it has a name, a verified email and a signed agreement. Abandoned sign-ups are deleted on a schedule without touching real accounts.
  • Money is stored in whole cents and multipliers in basis points, so important data never uses a float. Balances are built per currency, so supporting a new currency means adding a column, not converting data.
  • Important data is never denormalised. Lifetime spend, and which balance paid for a post, are both derived from the ledger.
  • Public uids are random and start with a prefix that says what kind of record they belong to. Internal ids stay plain integers.
  • PostgreSQL and PostGIS
  • Prisma
  • Kysely
  • AWS

Seventy-four migrations

Shipped 74 schema migrations to Tagly's live database. The new shape goes live next to the old one first, the old columns and tables are only dropped later, once nothing reads them and the workers have moved to the new shape.

  • Prisma
  • PostgreSQL and PostGIS
  • AWS

Completely restructured onboarding based on funnel data

Rebuilt Tagly's onboarding after the funnel showed a big drop-off at the first step, connecting Instagram. Onboarding now starts with an email code, or Apple or Google sign-in. Connecting Instagram moved to the end and became optional, which doubled the onboarding completion rate.

  • PostHog
  • React Native

Infra

Three environments, nine installable apps

Set up three environments for the whole Tagly ecosystem: development runs locally, and staging and production run on AWS. The three apps come to nine builds, and all nine install side by side on one phone. Any environment can be tested on a real device without touching production data. Staging and production are fully separated, each with its own database, cache and storage, across 13 AWS services in total.

  • AWS
  • EAS Build and Submit
  • Expo

Everything ships from GitHub Actions

Built the GitHub Actions pipelines that ship every part of Tagly, so nothing is deployed by hand. One pipeline ships the REST API and all 7 background services. Another builds and submits the apps, per environment and platform. A third deploys the marketing, landing and redirect sites. Each pipeline checks the result against what AWS, EAS and Amplify report back.

  • GitHub Actions
  • AWS
  • EAS Build and Submit

QR stickers with referral attribution

Built the referral attribution behind the QR sticker on the counter of every business Tagly works with. Everyone who joins through a sticker is credited to whoever invited them. Scanning a sticker opens the app if it's installed, or a landing page carrying the business's referral code if it isn't. The referral code survives the trip through the app store: AppsFlyer retrieves the code on the first open after install, and the app saves it locally.

  • AppsFlyer
  • Next.js
  • Expo

Errors and funnels tracked in PostHog

Set up error tracking and funnels in PostHog, so problems and drop-offs show up in one place. The REST API and all 7 background services send every error to PostHog. The customer and business apps report errors from their critical flows, and track how far people get through each funnel.

  • PostHog

Frontend

Shared design system across three apps

Built the components and design tokens shared by all three apps, so a design change only happens once, in the shared package. One business-management form serves 9 different screens across the admin and business apps. Each screen hands the form its own pair of functions for reading and saving data.

  • React Native
  • TypeScript

Map of nearby businesses

Built a map that loads businesses in tiles as you pan, showing each business with how much you can earn for sharing it. Markers keep their own selected state and are drawn separately for iOS and Android. A list along the bottom of the screen lets you cycle through every available business without moving the map.

  • React Native
  • Expo

Tagly's marketing site, invite page and redirect page

Built Tagly's three web surfaces. The business-facing marketing site and the user-facing invite page, which opens when someone taps an invite link, are both built in Next.js and React, in English and Czech. The third is a dependency-free static page that sends people back into the app after an OAuth sign-in or a Stripe flow.

  • Next.js
  • React
  • Tailwind CSS
  • i18next

Design

App design built around the core audience

Designed the screens of Tagly's three React Native apps. The theme is built for Tagly's core audience, women aged 18 to 35: warm coffee and beige tones, with butter yellow and baby blue accents. All three apps share that palette and one set of components. Below are some of the screens.

  • React Native
  • Expo

Web design

Designed and built Tagly's business-facing marketing site and user-facing invite page. Both ship in English and Czech and are deployed on Amplify. This site is built with the same stack: Next.js, React and Tailwind.

  • Next.js
  • React
  • Tailwind CSS