Back
February 12, 2026
5 min read

Sharing Content From Anywhere: PWA, Chrome Extension, and a Laravel API

A Progressive Web App and Chrome Extension that let me save and annotate interesting content from my phone or browser, with automatic metadata extraction.

Sharing Content From Anywhere: PWA, Chrome Extension, and a Laravel API

When building my personal site I realised I want to blog about things I have to share, but probably even more often I want to share other thought leaders content with maybe just a bit of my own commentary on it.

I needed something that was not a bookmarking tool buried in a browser. Something that feels native: on my phone, the share button goes directly to the app. On desktop, one click from any browser tab.

The result is a three-part system: a Laravel API endpoint, a Progressive Web App for mobile, and a Chrome Extension for desktop. All three share a single API contract and authentication method.

CLOUDFLARE PAGES Shares PWA Web Share Target API · Android share sheet CHROME Extension Manifest V3 · One-click from any tab POST /shares POST /shares LARAVEL API POST /api/v1/shares Sanctum bearer token · URL + optional commentary OpenGraphService Auto-extract metadata · YouTube API · X/Twitter parsing · SSRF protection Embedded + Searchable by AI

The Backend: One Endpoint, Three Clients

Everything flows through POST /api/v1/shares, authenticated via a Laravel Sanctum bearer token. The request is minimal — a URL and optional commentary. The backend does the rest.

An OpenGraphService takes the submitted URL and auto-extracts metadata. It fetches the page, parses OpenGraph tags for title, description, image, site name, and author, then detects the source type. YouTube URLs get special treatment: if a YouTube Data API key is configured, the service calls YouTube's API directly for proper thumbnails and channel names instead of relying on OG tags. X/Twitter URLs extract the tweet ID and author handle from the URL structure.

The service includes SSRF protection — it validates that URLs resolve to public IP addresses before fetching, blocking attempts to hit internal services through crafted URLs.

Once created, the share model's HasEmbedding trait fires, dispatching an embedding job. Within seconds, the new share is searchable through the AI chatbot's hybrid search pipeline. Save a link about React Server Components from your phone, and the chatbot can surface it when someone asks about React patterns.

The PWA and Web Share Target API

The Shares PWA is a vanilla HTML, CSS, and JavaScript app hosted on Cloudflare Pages. No build tools, no framework — the entire application is small enough that a framework would add more complexity than the app itself contains.

The key feature is the Web Share Target API. The PWA's manifest.json declares a share_target, which tells Android to include the app in the native share sheet. When I'm reading an article in Chrome or watching a YouTube video, I tap the share button, select the Shares PWA, and the URL arrives ready to submit.

The messy reality of share targets is that different apps send data differently. Some put the URL in the url parameter, some embed it in the text parameter alongside other content, and some use title. The extractSharedUrl() function handles all these cases: it checks the explicit url parameter first, then tries to extract a URL from the text parameter using a regex, then falls back to title. It validates that the result is actually an HTTP or HTTPS URL before accepting it.

Source type detection mirrors the backend logic — YouTube, X/Twitter, and generic webpage — updating a visual icon in the UI so I can see at a glance what I'm sharing.

The service worker uses a stale-while-revalidate strategy for the app shell (HTML, CSS, JS, icons) while ensuring API calls are never cached. This means the PWA loads instantly even on flaky mobile connections, but share submissions always go directly to the server.

Authentication is a bearer token stored in localStorage, configured through a setup screen that tests the connection before saving. Simple, effective, and appropriate for a single-user tool.

The Chrome Extension

The Chrome Extension covers the desktop workflow. It's a Manifest V3 extension with minimal permissions: activeTab (reads the current tab's URL only when the popup opens) and storage (persists the API URL and bearer token via chrome.storage.sync).

When I click the extension icon, the popup auto-fills with the current tab's URL, detects the source type, and focuses the commentary field. The workflow is optimised for speed: open popup, optionally type a note, hit share. The URL field is read-only since it's always the current tab.

Settings (API URL and bearer token) live on a separate options page that opens in a full tab. Like the PWA, it includes a connection test that verifies the token by hitting GET /api/user before saving.

The extension mirrors the PWA's source type detection and error handling. Both handle 401 (invalid token) and 422 (validation errors) responses with specific, helpful messages rather than generic failure screens.

Why This Approach

The Web Share Target API is underused. Most developers default to building native apps or complex bookmark managers when a PWA with a share target covers the mobile use case natively. Combined with a Chrome Extension for desktop, the entire sharing surface is covered without a single native app.

The vanilla JS choice was deliberate — these are micro-apps with a single responsibility. The PWA is under 500 lines of JavaScript. The extension popup is similarly small. React or Vue would add a build step, a node_modules directory, and framework overhead to apps that don't need state management, routing, or component trees.

Both tools feed into the same backend, which feeds into the same embedding pipeline, which feeds into the same AI search. Save a link from your phone, and the chatbot can discuss it moments later. That's the payoff of a well-connected architecture.

This is part of the Building nickbell.dev series. Read about the AI agent or Filament as a headless CMS.