Skip to content

Find a component

Loading the directory…

↑ ↓ to select · Enter to open · Esc to closeBrowse all →
Contributor login

Bright Data Sholajegede

Cache Bright Data SERP and Web Unlocker results in Bijection with configurable TTLs and reactive queries.

Bijection source
git clone https://github.com/bijectionhq/bright-data-sholajegede.git
cd bright-data-sholajegede
git checkout 56e3626498bb4a680b42bc615477bbe4575947e7

Bijection repository access is required. Request access.

Description

Cache Bright Data SERP and Web Unlocker results in Bijection with configurable TTLs and reactive queries.

Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.

Available as a reference

Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.

Getting started

  1. Get the source at the revision above and read its package documentation.
  2. Check the required Bijection SDK version, dependencies, and external service credentials.
  3. Follow the package setup instructions and the guide to using components.
  4. Exercise the component in your deployment according to your project’s verification rules.

Open source

Maintained source: bijectionhq/bright-data-sholajegede. Based on sholajegede/convex-bright-data. License: Apache-2.0. Consult the repository for license terms, notices, and contributor attribution.

From the upstream publisher

Cache Bright Data SERP and Web Unlocker results in Convex with configurable TTLs and reactive queries.

Explore the demo ↗

Upstream overview

From the upstream package documentation.

This component wraps Bright Data's SERP API and Web Unlocker with reactive Convex caching. Search results and scraped web content are stored in component-owned tables with configurable TTLs, enabling reactive queries that update automatically when cache refreshes. Developers get instant cached responses via useQuery with no re-fetching until data expires.

Use cases

From the upstream package documentation.

  • Build a search aggregation app that caches Google search results and updates the UI reactively when fresh data arrives
  • Create a competitive intelligence dashboard that scrapes competitor websites and stores content with 6-hour TTLs
  • Implement a news monitoring system that searches specific verticals (news, shopping) and maintains fresh results in Convex tables
  • Build a content research tool that scrapes multiple URLs and provides real-time cache status with fetchedAt and expiresAt timestamps
  • Add web scraping capabilities to an existing Convex app without managing separate caching infrastructure

How it works

From the upstream package documentation.

The component stores Bright Data API responses in dedicated Convex tables with configurable TTL settings. When you call brightData.search() or brightData.scrape() from Convex actions, it checks the cache first and only hits the Bright Data API if data is stale or missing.

The key pattern involves two functions per operation: an action that fetches/caches data (like searchWeb) and a query that reads cached results (like getCachedSearch). Frontend components use useQuery on the cached data functions to get reactive updates whenever the cache refreshes.

Setup requires instantiating the BrightData class with your API credentials and zone names, then calling component queries via ctx.runQuery(components.brightData.lib.getSearch, {...}). The component handles cache invalidation through the invalidate() method and supports search verticals (news, shopping, images) plus recency filtering.

Upstream package FAQ

How does the Bright Data Convex component handle cache TTLs?

The @sholajegede/convex-bright-data component supports configurable TTLs per request or global defaults (1 hour for searches, 6 hours for pages). Cached data includes fetchedAt and expiresAt timestamps, with an isFresh boolean indicating if data is still within TTL.

Can I force refresh cached Bright Data results?

Yes, the Bright Data component provides an invalidate method that deletes cached entries for specific queries or URLs. This forces a fresh fetch from Bright Data APIs on the next request while preserving the reactive caching pattern.

What Bright Data services does this Convex component support?

The @sholajegede/convex-bright-data component supports Bright Data's SERP API for Google search results (web, news, shopping, images, videos) and Web Unlocker for page scraping. Both services are wrapped with the same TTL-based caching and reactive query pattern.

How do reactive queries work with cached Bright Data results?

The component stores Bright Data results in Convex tables. Call the action once to fetch and cache data, then use useQuery on the cached results. Convex automatically notifies all subscribers when cache updates, eliminating the need for polling or manual refresh logic.

Use with agents and CLI

Give your coding agent the component’s source identity and setup guidance.

agent-prompt.md
Help me integrate Bright Data Sholajegede with Bijection.

Read: https://bijection.com/components/bright-data-sholajegede/SKILL.md

Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.

Upstream README.md

View repository ↗

Documentation from sholajegede/convex-bright-data, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.

@sholajegede/convex-bright-data

A Convex component that wraps Bright Data's SERP API and Web Unlocker with reactive caching. Search results and scraped page content are stored in component-owned Convex tables with configurable TTLs — apps query cached results reactively, with no re-fetching if data is still fresh.

Found a bug? Feature request? File it here.

Features

  • SERP search via Bright Data's SERP API — Google search results cached in Convex
  • Web scraping via Bright Data's Web Unlocker — page content cached in Convex
  • Reactive queries — useQuery on cached results, live updates when cache refreshes
  • Configurable TTLs — per-request or global defaults for searches and pages
  • Cache invalidation — force re-fetch any query or URL on demand
  • No re-fetching — returns cached data instantly if still within TTL

Prerequisites

  • A Bright Data account with:
    • A SERP API zone (default zone name: serp_api1)
    • A Web Unlocker zone (default zone name: web_unlocker1)
    • An API token

Installation

npm install @sholajegede/convex-bright-data

Add the component to your convex/convex.config.ts:

import { defineApp } from "convex/server";
import brightData from "@sholajegede/convex-bright-data/convex.config.js";

const app = defineApp();
app.use(brightData);

export default app;

Usage

Instantiate the client in your Convex functions file, passing your Bright Data credentials:

// convex/brightData.ts
import { components } from "./_generated/api.js";
import { BrightData } from "@sholajegede/convex-bright-data";

export const brightData = new BrightData(components.brightData, {
  BRIGHTDATA_API_TOKEN: process.env.BRIGHTDATA_API_TOKEN!,
  BRIGHTDATA_SEARCH_ZONE: process.env.BRIGHTDATA_SEARCH_ZONE,       // optional, default: "serp_api1"
  BRIGHTDATA_WEB_UNLOCKER_ZONE: process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE, // optional, default: "web_unlocker1"
  DEFAULT_SEARCH_TTL_MS: 1000 * 60 * 60,   // optional, default: 1 hour
  DEFAULT_PAGE_TTL_MS: 1000 * 60 * 60 * 6, // optional, default: 6 hours
});

Security note: Your Bright Data API token is passed through Convex action arguments and traverses the Convex runtime on the server side. Always load it from environment variables using process.env in your app's Convex functions — never hardcode it or expose it in client-side code.

npx convex env set BRIGHTDATA_API_TOKEN your_token_here

Search the web

// convex/myFunctions.ts
import { action, query } from "./_generated/server.js";
import { components } from "./_generated/api.js";
import { brightData } from "./brightData.js";
import { v } from "convex/values";

// Fetch (or return cached) search results
export const searchWeb = action({
  args: { query: v.string() },
  handler: async (ctx, args) => {
    return await brightData.search(ctx, { query: args.query });
  },
});

// Reactive query — subscribe to cached results from the frontend.
// This is the key pattern: call searchWeb once to fetch and cache,
// then useQuery on getCachedSearch to get live updates whenever the
// cache refreshes. No polling needed — Convex pushes updates automatically.
export const getCachedSearch = query({
  args: { query: v.string() },
  handler: async (ctx, args) => {
    return await ctx.runQuery(components.brightData.lib.getSearch, {
      query: args.query,
    });
  },
});
// React component — subscribes reactively, re-renders when cache updates
const results = useQuery(api.myFunctions.getCachedSearch, { query: "convex database" });
// results.isFresh   — true if still within TTL, false if stale
// results.results   — JSON string of search results from Bright Data
// results.fetchedAt — timestamp of when data was last fetched
// results.expiresAt — timestamp of when the cache entry will expire

Scrape a page

// Fetch (or return cached) page content
export const scrapePage = action({
  args: { url: v.string() },
  handler: async (ctx, args) => {
    return await brightData.scrape(ctx, { url: args.url });
  },
});

// Reactive query — subscribe to cached page content from the frontend.
// Same pattern as search: scrape once, then useQuery for live updates.
export const getCachedPage = query({
  args: { url: v.string() },
  handler: async (ctx, args) => {
    return await ctx.runQuery(components.brightData.lib.getPage, {
      url: args.url,
    });
  },
});
// React component
const page = useQuery(api.myFunctions.getCachedPage, { url: "https://example.com" });
// page.content    — raw HTML or text content of the scraped page
// page.isFresh    — true if still within TTL
// page.fetchedAt  — timestamp of last scrape

Invalidate cache

// Force a fresh fetch on the next call by deleting the cached entry
export const invalidateCache = action({
  args: {
    query: v.optional(v.string()),
    url: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    return await brightData.invalidate(ctx, args);
  },
});

How reactive queries work

The component stores search results and scraped content in its own Convex tables. When you call searchWeb or scrapePage, the result is written to those tables. Any frontend component subscribed via useQuery on getCachedSearch or getCachedPage receives the update instantly — no polling, no websocket management, no extra infrastructure. This is standard Convex reactivity applied to external data.

User triggers searchWeb action
        ↓
Bright Data SERP API called
        ↓
Result stored in component-owned searches table
        ↓
All useQuery subscribers notified automatically
        ↓
UI updates in real time

API

BrightData class

MethodDescription
search(ctx, { query, vertical?, recency?, ttlMs? })Search via Bright Data SERP API. Returns cached results if fresh.
scrape(ctx, { url, ttlMs? })Scrape a URL via Web Unlocker. Returns cached content if fresh.
invalidate(ctx, { query?, url? })Delete cached entry to force re-fetch on next call.

Reactive queries (call via ctx.runQuery)

FunctionDescription
components.brightData.lib.getSearch({ query })Get cached search result. Returns null if not yet fetched.
components.brightData.lib.getPage({ url })Get cached page content. Returns null if not yet fetched.

Both return { results/content, fetchedAt, expiresAt, isFresh }.

search verticals

Pass a vertical string to search specific Google verticals:

ValueVertical
(omit)Web search
nwsNews
shopShopping
ischImages
vidVideos

search recency

Pass a recency string to filter by date:

ValueRange
dPast day
wPast week
mPast month
yPast year

Example app

See example/ for a working Vite + React demo showing live SERP search and page scraping with reactive cache display.

Development

npm i
npm run dev

License

Apache-2.0

Keywords