Skip to content
SearchJet
React Search Library

Instant Search for React — One Hook, Your Components, No SDK

AI-Powered Search for Modern React Applications

Add AI-powered search to any React app in minutes. One HTTP request, a small hook you own, zero-config setup.

The Problem

React Search Options Are Limited

Building search in React means choosing between expensive SaaS, complex infrastructure, or months of custom development.

⚠

Algolia = Expensive + Complex

Algolia pricing scales aggressively as your user base grows, and the setup is more complex than most React projects need.

⚠

ElasticSearch = Infrastructure Nightmare

Self-hosted ElasticSearch requires DevOps expertise, dedicated servers, and ongoing maintenance that pulls your team away from product work.

⚠

Custom Solution = Months of Work

Building relevance, typo tolerance, faceting, and autocomplete from scratch takes months and rarely matches purpose-built search quality.

The Solution

SearchJet + React

No SDK needed — one HTTP request from a small hook you own, rendered with your own components. Built for any React stack.

A Hook You Own

Paste a ~25-line useSearchJet hook (fetch + debounce + AbortController) and get full control over search state and UI. Wire it to any component, any design system.

Your Components, Your UI

Results come back as plain JSON (id, title, content, url, excerpt), so you render them with your own components. Nothing to override.

TypeScript Friendly

No SDK types to learn. Describe the response (results, total, limit, offset) with a small interface for your data shape.

Zero Config

One GET request with your search key. Add limit, offset, sort, or filters when you need them, but never forced to configure.

Framework Agnostic

Works with Vite, Create React App, Next.js, Remix, Astro, or any React setup. Any HTTP client, everywhere.

No Bundle Cost

No search library to ship: the browser's built-in fetch does the work. No bloat, no performance hit.

Copy-Paste Integration

Two approaches — a simple search page or full control with filters

Basic Hook Usage

useSearchJet.js + SearchPage.jsx
// useSearchJet.js — ~25 lines you paste into your app (not a package)
import { useEffect, useState } from 'react';

const API = 'https://app.searchjetengine.com/api/v1/search';
const SEARCH_KEY = 'your_search_api_key'; // search-only key; never use the private key here

export function useSearchJet(query, { limit = 10, filters } = {}) {
  const [data, setData] = useState({ results: [], total: 0 });
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!query) { setData({ results: [], total: 0 }); return; }
    const controller = new AbortController();
    const timer = setTimeout(async () => {
      setLoading(true);
      const params = new URLSearchParams({ q: query, limit: String(limit) });
      if (filters) params.set('filters', filters);
      try {
        const res = await fetch(`${API}?${params}`, {
          headers: { Authorization: `Bearer ${SEARCH_KEY}` },
          signal: controller.signal,
        });
        setData(await res.json()); // { results: [...hits], total, limit, offset, ... }
      } catch {} // aborted or network error
      setLoading(false);
    }, 200); // debounce
    return () => { clearTimeout(timer); controller.abort(); };
  }, [query, limit, filters]);

  return { hits: data.results ?? [], total: data.total ?? 0, loading };
}

// SearchPage.jsx
import { useState } from 'react';
import { useSearchJet } from './useSearchJet';

export default function SearchPage() {
  const [query, setQuery] = useState('');
  const { hits, total } = useSearchJet(query);

  return (
    <div>
      <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search anything..." />
      {query && <p>{total} results</p>}
      {hits.map((hit) => (
        <article key={hit.id} className="p-4 border-b">
          <h3><a href={hit.url}>{hit.title}</a></h3>
          <p>{hit.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Full Component with UI

SearchWithFilters.jsx
// SearchWithFilters.jsx — uses the useSearchJet hook from the left
import { useState } from 'react';
import { useSearchJet } from './useSearchJet';

const CATEGORIES = ['all', 'docs', 'blog', 'product'];

export function SearchWithFilters() {
  const [query, setQuery] = useState('');
  const [type, setType] = useState('all');

  // "filters" only works on attributes marked filterable in your index
  // settings; otherwise the API returns error code INVALID_FILTER.
  const filters = type === 'all' ? undefined : `type = "${type}"`;
  const { hits, total, loading } = useSearchJet(query, { limit: 20, filters });

  return (
    <div className="flex gap-8">
      {/* Sidebar filters */}
      <aside className="w-64">
        {CATEGORIES.map((c) => (
          <label key={c} className="block">
            <input type="radio" checked={type === c} onChange={() => setType(c)} /> {c}
          </label>
        ))}
      </aside>

      {/* Results */}
      <main className="flex-1">
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search products..."
          className="w-full p-3 border rounded-lg"
        />
        {loading ? (
          <p>Searching...</p>
        ) : (
          <>
            {query && <p>{total} results</p>}
            {hits.map((hit) => (
              <article key={hit.id} className="p-4 border-b">
                <h3><a href={hit.url}>{hit.title}</a></h3>
                <p>{hit.excerpt}</p>
              </article>
            ))}
          </>
        )}
      </main>
    </div>
  );
}

Need a complete starter project?

View GitHub Examples
Illustrative Example

Before and After

Illustrative example of a React app adding hosted search. Your results will vary.

MetricBeforeAfterImpact
Time to ImplementWeeksDaysMuch faster launch
Bundle Impact55KB (Algolia)None — built-in fetchNo SDK to ship
Search LatencySlower on large datasets<150msFaster results
Annual CostsUsage-based (Algolia)$0-228 (Free or Pro)A fraction of the cost

Frequently Asked Questions

Everything you need to know about SearchJet for React

Does SearchJet work with React 18?
Yes. SearchJet is a REST API you call with fetch, so it works with React 18 including concurrent features, Suspense boundaries, and streaming SSR. No hydration issues.
What React versions are supported?
Any React version with hooks (16.8+) can use the sample hook below. Works with Vite, Create React App, Next.js, Remix, Astro, and any React-based setup.
Is there a useSearch hook?
There is no SDK to install. Instead, copy the ~25-line useSearchJet hook below: it calls GET /search with fetch, debounces keystrokes, and cancels stale requests. You own the code and can extend it with filters, sorting, or pagination.
Can I customize the UI completely?
Absolutely. The API returns plain JSON, so you build any UI from scratch with your own components and design system.
Does it work with React Native?
Yes. The same hook works in React Native because it only uses fetch. Render the results with native components.
How does it handle large datasets?
Search runs on external infrastructure, so dataset size doesn't affect your React bundle or client-side performance. Results stream in as users type.

Ready to Add Search to Your React App?

Join developers building exceptional search experiences with SearchJet

Already have an account? Log in

Related Use Cases