Contributing to the Content Clipping Pandemic
January 25, 2026
The Big 26
Happy new year! In New Year's fashion, I wanted to reflect on what I worked on over the past fall semester of college, which was my final semester. I also picked up writing again since I'm unemployed at home, searching for a full-time job, and needed something to do.
Sneaker Reselling Connections Run Deep
This project started when I received a connection request from the founder of a company called Hidden Studios. I'd never heard of them, so I chatted with him and found out he's an ex-sneaker reseller who became a marketing/advertising manager for brands looking to increase awareness through virtual ads. They had an impressive portfolio of past work through partnerships with companies like Mountain Dew to place ads in games like Fortnite - pretty neat stuff.
Interested, I asked what they needed from me, and they were looking to expand their offerings and tap into the content-clipping market.
They wanted a platform where creators and managers could run clipping campaigns, hire clippers to create short-form videos, publish to social platforms, and get paid based on performance. There weren't many constraints besides using Next.js, Supabase, and Vercel. So, I set off to build Vyral.
Full details of the project requirements can be found here.
Scraping Social Media Data
The most important question for a project like this is always: how do we get the necessary data? Since this app needs post metrics from multiple platforms, I knew it wasn't realistic for me to build my own scrapers. Someone would have to maintain them long-term, and there's just too much overhead when scraping social media sites.
Coincidentally, I kept seeing sponsored segments on YouTube about a platform called BrightData (formerly Luminati Networks). If you've ever worked with web scraping or proxies, you've probably heard of them.
Looks like the sponsored segments worked, because I poked around and found they offered exactly what I needed: web APIs for social media scrapers. Since BrightData started as a proxy network, they already had the heavy infrastructure for large-scale scraping like proxies, anti-bot measures, retries, and job management. So I used BrightData for batch scraping jobs collect post metrics from Instagram Reels, YouTube Shorts, TikTok, and Facebook Reels.
Scraping Jobs
To make scraping reliable (and affordable), I treated it like a queueing problem rather than a one‑off cron. Each post URL gets a durable metrics_jobs row in Postgres, and jobs are claimed atomically using FOR UPDATE SKIP LOCKED so multiple schedulers can run without double‑processing. I leaned into Supabase’s stack: a scheduler Edge Function runs every few minutes and uses ensure_metrics_jobs and claim_metrics_jobs RPCs to backfill missing work, claim due jobs, and kick off BrightData async runs. That scheduler itself is triggered by pg_cron inside Postgres, which calls the Edge Function endpoint on an interval, so the schedule lives alongside the data model.
On completion, BrightData hits a worker webhook that normalizes the returned data, whether it be clean JSON or malformed strings, and maps platform‑specific fields into a single {views, likes, comments, shares} object. Those rows are inserted into a time‑series table, and the job is rescheduled based on a per‑URL cadence (default hourly, configurable per post).
Failure handling is simple: failed runs mark the job as pending again with a backoff delay, and errors are logged to a dedicated table for debugging. I also added a manual refetch endpoint, gated with per‑user cooldowns and per‑tenant daily caps so it can’t be abused. This creates a pipeline that’s resilient to inconsistent data and flaky providers while staying cheap and predictable. Because I used the database queue and time‑series table as the source of truth, the system can retry, recover, and stay consistent when the scraper errors.
Payments & Payouts
Vyral uses Stripe Connect Express for payments since it splits onboarding from platform logic and keeps sensitive bank details off my servers. Creators go through a dedicated onboarding flow, and I keep a local payout_accounts record in Supabase that mirrors their Stripe account status via webhooks (account.updated, transfer.*). The payout workflow itself is intentionally staged, where managers/admins preview a statement first, then create a statement, and only later execute it. Under the hood, payout math is done in Postgres with RPCs so the calculation is consistent across API and UI. The preview uses time‑series deltas, per‑URL min/max within a period, plus campaign rules like CPM, caps, and bonuses to produce a line‑item breakdown and totals. That preview is then used to generate immutable statements, which maintains integrity for auditing.
On the automation side, a weekly batch function generates statements for the last full Mon–Sun UTC week, then creates Stripe transfers with an idempotency key tied to the statement id. That makes payouts safe to retry without double‑paying. After a statement is paid, I update baseline "last paid views" per URL so future payouts only count incremental growth. The result is a payments system that is both creator‑friendly and platform‑safe.
Multi-tenant Security & RLS
To handle multi-tenancy, I used Postgres for access control instead of just UI checks. Every table is scoped by tenant_id and protected with row‑level security, and permissions are modeled explicitly as enums that map to roles (tenant_admin, manager, creator). That means reads and writes are allowed only when the user’s role has the correct permission, and platform admins can bypass tenant checks through a separate global table. Business workflows, like inviting users, creating campaigns, approving rules, or invalidating URLs, are implemented as RPCs so the enforcement lives next to the data. The app only uses those RPCs (and never a raw service‑role client in the browser), which keeps the attack surface small.
On the server side, every request resolves an "active tenant" from a cookie and verifies that the user is still a member before running queries. If there’s no valid tenant, the user gets redirected to the organization selection page. This active‑tenant scoping pattern removes an entire class of "forgot to filter by tenant_id" bugs. I also used triggers to enforce invariants that could be bypassed by a bad client, such as auto‑enqueuing metrics jobs only when URLs are approved and valid. Because of these decisions, cross‑tenant leakage is prevented by design, and most permission mistakes fail closed at the database layer rather than in UI code.
Closing Remarks
That’s the story of Vyral - an exciting but challenging 3-week sprint where I built a web app that could be used by people to get paid by clipping content creators.
You can checkout the Github repository for Vyral here and the Supabase Functions here.