All Experiments
╔══════════════════════════════════════════════════════════════╗
║  EXPERIMENT: Capture Pattern                                 ║
║  KEY METRIC: 0 OAuth providers → same functionality          ║
║  workway.co                                                  ║
╚══════════════════════════════════════════════════════════════╝
ValidatedJanuary 21, 2026

The Capture Pattern

Let people share what they find instead of scraping everything they might want.

What we were doing

We built a YouTube to Notion workflow. It watched a playlist and saved new videos automatically.

The setup

  1. 1. Connect YouTube
  2. 2. Connect Notion
  3. 3. Pick a playlist
  4. 4. We poll it every 15 minutes
  5. 5. New videos get saved with transcripts

Where it broke down

  • App review: YouTube wants us reviewed before users can connect
  • Token expiry: OAuth tokens expire, refresh logic breaks
  • Wasted polls: Most checks find nothing new
  • Playlist friction: People don't naturally add videos to playlists
  • Silent failures: When something breaks, nobody knows

The idea

What if the user just told us what to save? One click on the video they're watching. No playlist, no polling, no YouTube OAuth.

This works if

  • We can get transcripts without YouTube API access
  • Desktop and mobile both work
  • It's faster than the old way
  • People actually use it

How it works now

User sends us the URL. We scrape the transcript. Done.

Desktop

Browser extension

⌘⇧S

Fallback

Bookmarklet

Click in bookmarks bar

Mobile

Share sheet

Share → WORKWAY

The flow

  1. 1. Install workflow, connect Notion
  2. 2. Get the extension or bookmarklet
  3. 3. Watch a video, press ⌘⇧S
  4. 4. We scrape the transcript, save to Notion
  5. 5. Shows up in your dashboard

Why this works

Transcripts are in the page HTML. Anyone can see them. We just need the URL to fetch them ourselves. No API key, no OAuth, no rate limits.

What we built

The pieces

ComponentPurposeLOC
/share endpointURL detection, transcript scraping, Notion save~400
/share pageLanding page for shared URLs~350
Browser extensionToolbar button, context menu, keyboard shortcut~200
useBookmarklet hookShared bookmarklet code generation~25
CaptureToolsModalPost-install capture tools display~130

Transcript Extraction

// No API key needed - public page scraping
const html = await fetch(`https://youtube.com/watch?v=${videoId}`);
const captionTracks = html.match(/"captionTracks":(\[.*?\])/);
const trackUrl = JSON.parse(captionTracks)[0].baseUrl;
const transcript = await fetch(trackUrl); // XML format

Before and after

Before

  • • Connect YouTube and Notion
  • • Poll every 15 minutes
  • • Handle token refresh
  • • Wait for app review
  • • Failures happen silently

After

  • • Connect Notion only
  • • User triggers when ready
  • • No tokens to manage
  • • No review needed
  • • Errors show immediately

Numbers

MetricBeforeAfter
OAuth providers21
Setup time~5 min~1 min
User action requiredNone (passive)1 click per capture
Failure visibilityBackground logsImmediate UI
Intent signalNoisy (all playlist adds)Clear (explicit action)

What we learned

This showed us

  • • You don't need OAuth for public data
  • • When someone clicks, they meant to — that's a clearer signal than automation
  • • Extension plus bookmarklet plus mobile share covers everyone
  • • Less code means fewer things that break

We don't know yet

  • • Whether scraping stays reliable (YouTube could change their HTML)
  • • Whether people prefer clicking over "set and forget" automation
  • • How this holds up at scale
  • • What happens when content isn't public

Trade-offs we made

  • User does more: One click per video instead of automatic
  • Fragile scraping: If YouTube changes their page, we break
  • Extension friction: Desktop users need to install something

When this makes sense

Use it when

  • • The data is public anyway
  • • Intent matters more than volume
  • • OAuth would be a pain to set up
  • • It doesn't need to run in the background

Skip it when

  • • You need private data
  • • It's bulk processing
  • • Background sync is the point
  • • Users won't install an extension

If you want to do this

The files

workway-platform/
├── apps/api/src/routes/share.ts        # API endpoint
├── apps/web/src/routes/share.tsx       # Landing page
├── apps/web/src/routes/extension.tsx   # Install instructions
├── apps/web/src/lib/hooks/useBookmarklet.ts
├── apps/web/src/components/
│   ├── CaptureToolsModal.tsx
│   └── ShareToolsSection.tsx
└── apps/extension/                     # Chrome extension
    ├── manifest.json
    ├── background.js
    ├── popup.html
    └── popup.js

The steps

  1. 1. Build a /share endpoint that takes URLs
  2. 2. Add scraping for your content type (YouTube, etc.)
  3. 3. Make a landing page that shows progress
  4. 4. Build a browser extension
  5. 5. Add share_target to your PWA manifest
  6. 6. Add a bookmarklet for people who skip extensions

The result

It worked

We removed YouTube OAuth. Setup went from five minutes to one. Errors are visible instead of silent. The workflow does the same thing with half the complexity.

The transcript scraping works. The extension works. People can use it without us getting reviewed by YouTube.

Still figuring out

  • Long-term reliability: Does scraping hold up when YouTube changes things?
  • User preference: Do people actually prefer clicking over automation?
  • Extension installs: How many people bother to install it?