Social Lookup Package

The shared profile shape and SocialScraper interface that each social vendor implements

Overview

@zooly/social-lookup is the contract for reading a public social profile. It has no vendor, no token, and no network calls. Each vendor lives in its own package and returns a SocialScraper. Callers depend on this package, then plug in whichever vendor they want.

  • Location: packages/social-lookup
  • Implementation in use: @zooly/social-brightdata (createBrightDataSocialScraper). Onboarding research uses this. @zooly/social-apify is deprecated and nothing in the product calls it. Bright Data is cheaper: free for 5,000 profiles a month, then $1.50 per 1,000.

@zooly/social-scraper is a different, older package (Scrapfly, follower counts). It does not implement this interface.

The interface

import type { SocialScraper } from "@zooly/social-lookup";
import { createBrightDataSocialScraper } from "@zooly/social-brightdata";

const scraper: SocialScraper = createBrightDataSocialScraper();

await scraper.lookupSocialProfile("INSTAGRAM", "@janekim");
await scraper.lookupSocialProfile(
  "INSTAGRAM",
  "https://www.instagram.com/janekim/",
);
await scraper.lookupSocialHandle("@janekim");
await scraper.lookupSocialHandle("https://www.linkedin.com/in/williamhgates");

lookupSocialProfile checks one network. lookupSocialHandle checks every network for a bare handle, or only the network in a profile URL. LinkedIn is looked up only from a linkedin.com/in/ link.

A result is found, not_found, or error. found carries one SocialProfile: name, bio, photo, follower counts, and the vendor's raw item. Tokens and HTTP clients stay on the factory in the vendor package, so a caller can swap vendors without learning that vendor's API.

Shared parsing

Handle and profile-URL parsing lives here, so every vendor treats @janekim, janekim, and a full profile URL the same way.

FileRole
src/scraper.tsSocialScraper
src/types.tsSocialProfile, SocialLookupResult, SocialPlatform
src/handle.tsHandle and profile-URL parsing