kagi

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: Unlicense Imports: 12 Imported by: 0

README

kagi-go-sdk

CI Go Reference Go Version

A handbuilt, idiomatic Go SDK for the Kagi Search API.

Designed to be ergonomic, production-ready, and easy to vendor — covering the full API surface with clean types, transparent retries, rate-limit handling, and proper context propagation.

Why this SDK

  • Zero external dependencies. Standard library only — go.mod has no require entries beyond the Go version itself. Safe to vendor, trivial to audit.
  • Idiomatic Go. Functional options, typed request/response structs, context.Context on every call, an errors.Is / errors.As-compatible error hierarchy.
  • Production-ready. Transparent retries with exponential backoff plus full jitter, Retry-After honoring, parsed error envelopes with trace IDs.
  • Handwritten, not generated. Clean field names, real godoc on every export, no pointer soup, typed enums instead of bare string constants.

vs. kagisearch/kagi-openapi-golang

Kagi publishes an official client generated from their OpenAPI spec. It is the right choice if you want lockstep with the spec; pick this SDK when you'd rather have ergonomics and built-in resilience.

kagi-go-sdk (this) kagisearch/kagi-openapi-golang
Source Handwritten OpenAPI-generated
External dependencies None Generator runtime + transitive deps
Error model Sentinel hierarchy (ErrUnauthorized, ErrRateLimited, ErrBadRequest, ErrServerError) wrapped by *APIError Generic *GenericOpenAPIError
Enums Typed (Workflow, TimeRelative, DomainRuleKind) String constants
Retries on 429 / 5xx Built-in, transparent, jittered backoff, honors Retry-After Not provided — caller's responsibility
context.Context on every call Yes Yes
Godoc coverage Every exported symbol Generated stubs
Vendoring footprint Single module Module + generated client tree

Install

go get github.com/hra42/kagi-go-sdk

Requires Go 1.26+.

Quick start

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	kagi "github.com/hra42/kagi-go-sdk"
)

func main() {
	client := kagi.NewClient(os.Getenv("KAGI_API_KEY"))

	res, err := client.Search(context.Background(), kagi.SearchRequest{
		Query: "context propagation in go",
	})
	if err != nil {
		log.Fatal(err)
	}

	for _, hit := range res.Data.Search {
		fmt.Printf("%s\n  %s\n\n", hit.Title, hit.URL)
	}
}

API reference

The full API surface is two methods on *Client. Every method takes a context.Context and a typed request struct, returns a typed response struct, and reports errors as *APIError values wrapping one of four sentinel errors (see Error handling).

func (c *Client) Search(ctx context.Context, req SearchRequest) (*SearchResult, error)

SearchRequest fields:

Field Type Notes
Query string Required. The search query.
Workflow Workflow WorkflowSearch (default) / WorkflowImages / WorkflowVideos / WorkflowNews / WorkflowPodcasts.
LensID string Saved-lens ID or full https://kagi.com/lenses/... URL.
Lens *Lens Inline lens (site/keyword filters, file type, time window, region).
Filters *SearchFilters Coarse filters: Region, After, Before. Take priority over Lens.
Extract *SearchExtract Opt in to inline page extraction for top results (Count, Timeout). Billed at the Extract rate.
Personalizations *Personalizations Per-request DomainRule and RegexRule ranking tweaks (up to 1000 each).
Page int 1-indexed page, server range 1..10.
Limit int Result cap, server range 1..1024.
Timeout float64 Server-side time budget in seconds (0.5..4).
SafeSearch *bool Override server default (true). Leave nil to inherit.

SearchResult.Data groups hits into category buckets — Search, Image, Video, News, Podcast, PodcastCreator, AdjacentQuestion, DirectAnswer, InterestingNews, InterestingFinds, Infobox, Code, PackageTracking, PublicRecords, Weather, RelatedSearch, Listicle, WebArchive. Each is a []SearchHit; category-specific extras are exposed as raw JSON via SearchHit.Props.

A richer call combining a lens, ranking rules, and inline extraction:

safe := false
res, err := client.Search(ctx, kagi.SearchRequest{
	Query: "kagi search api",
	Lens: &kagi.Lens{
		SitesIncluded: []string{"help.kagi.com"},
		TimeRelative:  kagi.TimeRelativeMonth,
	},
	Personalizations: &kagi.Personalizations{
		Domains: []kagi.DomainRule{
			{Domain: "blog.kagi.com", Kind: kagi.DomainRuleRaise},
			{Domain: "reddit.com", Kind: kagi.DomainRuleBlock},
		},
	},
	Extract:    &kagi.SearchExtract{Count: 3, Timeout: 2.0},
	Limit:      10,
	SafeSearch: &safe,
})
Client.Extract
func (c *Client) Extract(ctx context.Context, req ExtractRequest) (*ExtractResult, error)

ExtractRequest fields:

Field Type Notes
Pages []ExtractPage Required. 1..10 entries; each URL must be HTTPS.
Timeout float64 Bulk time budget in seconds (0.5..10).

A 200 response can include both successful Data entries and per-URL failures in Errors; partial success is not converted into a Go error.

res, err := client.Extract(ctx, kagi.ExtractRequest{
	Pages: []kagi.ExtractPage{
		{URL: "https://blog.kagi.com/kagi-search-api"},
		{URL: "https://help.kagi.com/kagi/api/search.html"},
	},
})
if err != nil {
	log.Fatal(err)
}

for _, p := range res.Data {
	fmt.Printf("=== %s ===\n%s\n", p.URL, p.Markdown)
}
for _, e := range res.Errors {
	fmt.Printf("failed %s: %s\n", e.Location, e.Message)
}
Enums
Type Values
Workflow WorkflowSearch, WorkflowImages, WorkflowVideos, WorkflowNews, WorkflowPodcasts
TimeRelative TimeRelativeDay, TimeRelativeWeek, TimeRelativeMonth
DomainRuleKind DomainRuleBlock, DomainRuleLower, DomainRuleRaise, DomainRulePin

Configuration

The client uses the functional options pattern:

client := kagi.NewClient(apiKey,
	kagi.WithTimeout(30*time.Second),
	kagi.WithRetries(3),
	kagi.WithBackoff(500*time.Millisecond, 30*time.Second),
	kagi.WithUserAgent("my-app/1.0"),
	kagi.WithHTTPClient(myHTTPClient),
	kagi.WithBaseURL("https://kagi.com/api/v1"),
)
Option Default Effect
WithTimeout(d time.Duration) 30s Sets http.Client.Timeout. Ignored when d <= 0.
WithHTTPClient(c *http.Client) &http.Client{Timeout: 30s} Replaces the transport. The client is shallow-copied at construction, so later mutation of your *http.Client does not affect the SDK.
WithBaseURL(s string) https://kagi.com/api/v1 Override endpoint. Must be an absolute URL with scheme + host; invalid values are silently ignored.
WithRetries(n int) 3 Max retries on 429 / 5xx / transient network errors. 0 disables retries; negative values clamp to 0.
WithBackoff(base, max time.Duration) 500ms, 30s Exponential backoff bounds; each delay is jittered uniformly in [0, window). max is also the ceiling for Retry-After. Non-positive values keep the default.
WithUserAgent(s string) kagi-go-sdk User-Agent header. Whitespace-only values are ignored.

The *Client is safe for concurrent reuse — construct it once and share it.

Error handling

Non-2xx responses are returned as *APIError, which unwraps to one of four sentinel errors:

Sentinel Trigger
ErrUnauthorized HTTP 401 — missing or invalid API key.
ErrRateLimited HTTP 429 — quota exhausted. APIError.RetryAfter is set when the server provides a Retry-After header.
ErrBadRequest HTTP 400 and other client-side 4xx (except 401).
ErrServerError HTTP 5xx — treated as transient by the retry layer.

Use errors.Is to classify and errors.As to read the response detail:

res, err := client.Search(ctx, req)
if err != nil {
	switch {
	case errors.Is(err, kagi.ErrRateLimited):
		var apiErr *kagi.APIError
		if errors.As(err, &apiErr) {
			log.Printf("rate limited, retry after %s (trace %s)", apiErr.RetryAfter, apiErr.TraceID)
		}
	case errors.Is(err, kagi.ErrUnauthorized):
		log.Fatal("check KAGI_API_KEY")
	case errors.Is(err, kagi.ErrBadRequest):
		var apiErr *kagi.APIError
		if errors.As(err, &apiErr) {
			for _, d := range apiErr.Details {
				log.Printf("  %s @ %s: %s", d.Code, d.Location, d.Message)
			}
		}
	default:
		log.Printf("transport or server error: %v", err)
	}
	return
}

Useful fields on *APIError:

  • StatusCode int / Status string — raw HTTP status.
  • Kind error — the sentinel this wraps.
  • Details []ErrorDetail — parsed entries (Code, URL, Message, Location) from the response envelope.
  • RetryAfter time.Duration — populated for 429 and 5xx when a Retry-After header is present.
  • TraceID stringmeta.trace from the response envelope; include this when contacting Kagi support.
  • Body []byte — raw (capped) response body, preserved when the envelope failed to parse.

Retries and rate limits

Requests that fail with HTTP 429, 5xx, or a transient network error are retried transparently. The retry layer:

  • Honors any server-provided Retry-After header (delta-seconds or HTTP-date), capped at WithBackoff's max.
  • Otherwise sleeps with exponential backoff plus full jitter: each attempt's window doubles up to max, and the actual delay is uniform in [0, window).
  • Aborts immediately if the request context is cancelled.

Only the final failure after the retry budget is exhausted is returned to the caller. Set WithRetries(0) to disable.

For manual rate-limit handling (for example, deferring work to a queue), check apiErr.RetryAfter once the retry budget has been exhausted.

Runnable examples

Each example is a self-contained package main. Set KAGI_API_KEY and run:

go run ./_examples/search           # minimal search
go run ./_examples/extract          # markdown extraction with per-URL error handling
go run ./_examples/search-advanced  # lens, filters, domain rules, inline extract
go run ./_examples/custom-client    # all Options + custom *http.Client + APIError classification

Contributing

Please read CONTRIBUTING.md before opening a PR. Short version: zero external dependencies — production code and tests — and every new exported symbol carries godoc.

Security

Please do not file public issues for security reports. See SECURITY.md — report privately via GitHub's security advisory flow.

License

Released into the public domain under the Unlicense.

Documentation

Overview

Package kagi is a handbuilt, idiomatic Go SDK for the Kagi Search API.

Construct a Client with NewClient and call Client.Search or Client.Extract. Transient failures (HTTP 429, 5xx, and network errors) are retried transparently with exponential backoff plus full jitter; see WithRetries and WithBackoff to tune the behavior. Errors are returned as *APIError values wrapping sentinel errors such as ErrUnauthorized and ErrRateLimited for use with errors.Is and errors.As.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnauthorized is returned for HTTP 401 responses, typically caused by a
	// missing or invalid API key.
	ErrUnauthorized = errors.New("kagi: unauthorized")

	// ErrRateLimited is returned for HTTP 429 responses. The accompanying
	// [APIError.RetryAfter] is populated when the server provides a
	// Retry-After header.
	ErrRateLimited = errors.New("kagi: rate limited")

	// ErrBadRequest is returned for HTTP 400 responses (and other non-401
	// client-side 4xx codes), indicating the request was malformed or rejected
	// by validation.
	ErrBadRequest = errors.New("kagi: bad request")

	// ErrServerError is returned for HTTP 5xx responses, which are treated as
	// transient by the retry layer.
	ErrServerError = errors.New("kagi: server error")
)

Sentinel errors returned for non-2xx API responses. Use errors.Is to test for a specific category, and errors.As with *APIError to access the full response detail.

if errors.Is(err, kagi.ErrRateLimited) {
    var apiErr *kagi.APIError
    if errors.As(err, &apiErr) {
        time.Sleep(apiErr.RetryAfter)
    }
}

Functions

This section is empty.

Types

type APIError

type APIError struct {
	// StatusCode is the HTTP status code of the response.
	StatusCode int
	// Status is the HTTP status text of the response (for example, "429 Too Many Requests").
	Status string
	// Kind is the sentinel error this APIError unwraps to.
	Kind error
	// Details holds the parsed errorDetail entries from the response envelope.
	// May be empty when the response body was missing, malformed, or did not
	// follow the expected envelope shape.
	Details []ErrorDetail
	// RetryAfter is the parsed Retry-After header duration. It is populated
	// for 429 and 5xx responses when the header is present, and is zero
	// otherwise.
	RetryAfter time.Duration
	// TraceID is the meta.trace value from the response envelope, useful when
	// contacting Kagi support. Empty when not provided.
	TraceID string
	// Body is the raw response body (capped) preserved for debugging when the
	// envelope could not be parsed.
	Body []byte
}

APIError is the concrete error type returned for non-2xx Kagi API responses. It implements [error] and unwraps to one of the sentinel errors (ErrUnauthorized, ErrRateLimited, ErrBadRequest, ErrServerError) so callers can match with errors.Is.

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface.

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

Unwrap returns the sentinel error this APIError wraps, enabling errors.Is matching against the package's exported sentinels.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a Kagi API client.

Clients are safe to reuse across requests after construction. Requests that fail with HTTP 429, 5xx, or transient network errors are retried transparently with exponential backoff plus full jitter; see WithRetries and WithBackoff to tune the behavior.

func NewClient

func NewClient(apiKey string, opts ...Option) *Client

NewClient creates a new Kagi API client using apiKey for authentication.

func (*Client) Extract

func (c *Client) Extract(ctx context.Context, req ExtractRequest) (*ExtractResult, error)

Extract fetches markdown content for one or more pages.

[ExtractRequest.Pages] is required; an empty slice or any entry with a blank URL is rejected without contacting the server. Server-side limits (1..10 pages, HTTPS scheme, timeout range) are enforced by the API and surface as a *APIError wrapping ErrBadRequest.

API errors are returned as a *APIError wrapping one of the package's sentinel errors (for example, ErrUnauthorized or ErrRateLimited); use errors.Is and errors.As to classify and inspect them.

func (*Client) Search

func (c *Client) Search(ctx context.Context, req SearchRequest) (*SearchResult, error)

Search performs a web search.

SearchRequest.Query is required; an empty or whitespace-only query is rejected without contacting the server. The returned SearchResult groups hits by category in SearchData; any category may be absent for a given query.

API errors are returned as a *APIError wrapping one of the package's sentinel errors (for example, ErrUnauthorized or ErrRateLimited); use errors.Is and errors.As to classify and inspect them.

type DomainRule

type DomainRule struct {
	// Domain is the pattern to match, for example "example.com" or a TLD
	// suffix such as ".co.uk".
	Domain string `json:"domain"`
	// Kind is how the matched domain should be handled.
	Kind DomainRuleKind `json:"kind"`
}

DomainRule adjusts ranking for a domain pattern.

type DomainRuleKind

type DomainRuleKind string

DomainRuleKind is the handling mode applied to a DomainRule.

const (
	DomainRuleBlock DomainRuleKind = "block"
	DomainRuleLower DomainRuleKind = "lower"
	DomainRuleRaise DomainRuleKind = "raise"
	DomainRulePin   DomainRuleKind = "pin"
)

Supported DomainRuleKind values.

type ErrorDetail

type ErrorDetail struct {
	// Code is a namespaced error code (for example, "extract.invalid_url").
	Code string `json:"code"`
	// URL points to documentation for the error code.
	URL string `json:"url"`
	// Message is a human-readable description of the error.
	Message string `json:"message,omitempty"`
	// Location identifies the request field where the error occurred, when
	// applicable (for example, "pages[0].url").
	Location string `json:"location,omitempty"`
}

ErrorDetail mirrors a single entry of the Kagi API's errorDetail schema.

type ExtractMeta

type ExtractMeta struct {
	// Trace is the request trace ID, useful when contacting Kagi support.
	Trace string `json:"trace"`
	// Node identifies the server node that fulfilled the request.
	Node string `json:"node"`
	// MS is the server-side processing time in milliseconds, excluding
	// network round-trip.
	MS int `json:"ms"`
}

ExtractMeta is the meta envelope of an extract response.

The exact set of fields is intended for debugging and may evolve over time; callers should treat it as advisory and avoid building hard dependencies on individual fields.

type ExtractPage

type ExtractPage struct {
	// URL is the HTTPS URL of the page to extract. Required.
	URL string `json:"url"`
}

ExtractPage identifies a single page to extract content from.

type ExtractRequest

type ExtractRequest struct {
	// Pages is the set of pages to extract. Server-side limits: 1..10
	// entries, each URL must use the HTTPS scheme.
	Pages []ExtractPage `json:"pages"`

	// Timeout is a time budget for the entire bulk extraction operation,
	// in seconds. Server-side range is 0.5..10; out-of-range values are
	// clamped by the server.
	Timeout float64 `json:"timeout,omitempty"`
}

ExtractRequest is the input to Client.Extract.

[ExtractRequest.Pages] is required and must contain between 1 and 10 entries (server-enforced). All other fields are optional and are omitted from the request body when left at their zero value.

type ExtractResult

type ExtractResult struct {
	// Meta carries trace and timing information about the request.
	Meta ExtractMeta
	// Data carries the extracted page results, in the same order as the
	// request's [ExtractRequest.Pages] when the server produced output for
	// each.
	Data []PageResult
	// Errors carries per-URL failures encountered during extraction. Empty
	// when every page extracted cleanly.
	Errors []ErrorDetail
}

ExtractResult is the response returned by Client.Extract.

A 200 response may include both extracted PageResult entries in [ExtractResult.Data] and per-URL failures in [ExtractResult.Errors]; the SDK does not convert that partial-success state into an error return.

type Image

type Image struct {
	// URL links directly to the image bytes.
	URL string `json:"url"`
	// Height is the image height in pixels, when reported by the server.
	Height int `json:"height,omitempty"`
	// Width is the image width in pixels, when reported by the server.
	Width int `json:"width,omitempty"`
}

Image describes an image associated with a SearchHit.

type Lens

type Lens struct {
	// SitesIncluded restricts results to these domains.
	SitesIncluded []string `json:"sites_included,omitempty"`
	// SitesExcluded removes results from these domains.
	SitesExcluded []string `json:"sites_excluded,omitempty"`
	// KeywordsIncluded requires results to contain these keywords.
	KeywordsIncluded []string `json:"keywords_included,omitempty"`
	// KeywordsExcluded removes results containing these keywords.
	KeywordsExcluded []string `json:"keywords_excluded,omitempty"`
	// FileType narrows to a specific file type (for example, "pdf").
	FileType string `json:"file_type,omitempty"`
	// TimeAfter restricts to pages updated on or after this date
	// (YYYY-MM-DD).
	TimeAfter string `json:"time_after,omitempty"`
	// TimeBefore restricts to pages updated on or before this date
	// (YYYY-MM-DD).
	TimeBefore string `json:"time_before,omitempty"`
	// TimeRelative restricts to a recent window relative to today.
	TimeRelative TimeRelative `json:"time_relative,omitempty"`
	// SearchRegion requests results localized to a region. Use an
	// ISO-3166-1 alpha-2 country code, or the special value "no_region".
	SearchRegion string `json:"search_region,omitempty"`
}

Lens is an inline description of a search lens.

A lens restricts or shapes the result set without altering the query. See the Kagi lenses documentation for behavior of each field.

type Option

type Option func(*config)

Option configures a Client.

func WithBackoff

func WithBackoff(base, maxBackoff time.Duration) Option

WithBackoff configures retry backoff timing.

base is the initial backoff window; the window doubles each attempt up to maxBackoff. Each delay is jittered uniformly in [0, window). Non-positive values leave the corresponding default in place (500ms base, 30s max).

The configured maxBackoff is also the ceiling applied to a server-provided Retry-After value.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL configures the base URL used for API requests.

The value must be an absolute URL (with scheme and host); invalid or empty values are ignored and the previously configured base URL is retained.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient configures the HTTP client used to make API requests.

The provided client is copied during NewClient construction so later SDK options do not mutate caller-owned state.

func WithRetries

func WithRetries(maxRetries int) Option

WithRetries configures the maximum number of retries for retryable requests (HTTP 429, 5xx, and transient network errors). The default is 3. Pass 0 to disable retries; negative values are treated as 0.

Retries are transparent to the caller: a successful retry returns the success response, and an exhausted retry budget returns the final error.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout configures the timeout used by the client's HTTP client.

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent configures the User-Agent header sent with API requests.

type PageResult

type PageResult struct {
	// URL is the URL of the extracted page, echoed from the request.
	URL string `json:"url"`
	// Markdown is the extracted page content rendered as markdown. May be
	// empty when extraction yielded no content for this page; check
	// [ExtractResult.Errors] for a matching error entry in that case.
	Markdown string `json:"markdown,omitempty"`
}

PageResult is the extracted content for a single page in an ExtractResult.

type Personalizations

type Personalizations struct {
	// Domains carries per-domain ranking adjustments (up to 1000 rules).
	Domains []DomainRule `json:"domains,omitempty"`
	// Regexes carries regex-based URL rewriting rules (up to 1000 rules,
	// max 1000 bytes per pattern).
	Regexes []RegexRule `json:"regexes,omitempty"`
}

Personalizations customizes result ranking for a single request.

type RegexRule

type RegexRule struct {
	// Regex is the pattern to match against the result URL.
	Regex string `json:"regex"`
	// Replacement is applied when Regex matches. Capture groups may be
	// referenced as "$1", "$2", and so on. Paths and query parameters are
	// preserved when not overwritten.
	Replacement string `json:"replacement,omitempty"`
}

RegexRule rewrites matching URLs in results.

type SearchData

type SearchData struct {
	// Search holds general web page results.
	Search []SearchHit `json:"search,omitempty"`
	// Image holds image results.
	Image []SearchHit `json:"image,omitempty"`
	// Video holds video results.
	Video []SearchHit `json:"video,omitempty"`
	// News holds news article results.
	News []SearchHit `json:"news,omitempty"`
	// Podcast holds podcast episode results.
	Podcast []SearchHit `json:"podcast,omitempty"`
	// PodcastCreator holds results for creators of podcasts.
	PodcastCreator []SearchHit `json:"podcast_creator,omitempty"`
	// AdjacentQuestion holds results gathered by asking related questions
	// alongside the original query. The associated question is exposed via
	// each hit's Props ("question" field).
	AdjacentQuestion []SearchHit `json:"adjacent_question,omitempty"`
	// DirectAnswer holds quick answers for queries like math expressions
	// or unit conversions.
	DirectAnswer []SearchHit `json:"direct_answer,omitempty"`
	// InterestingNews holds news pulled from Kagi's curated news index.
	InterestingNews []SearchHit `json:"interesting_news,omitempty"`
	// InterestingFinds holds small-web results from Kagi's small-web
	// index.
	InterestingFinds []SearchHit `json:"interesting_finds,omitempty"`
	// Infobox holds summary entries for a person, place, or thing.
	Infobox []SearchHit `json:"infobox,omitempty"`
	// Code holds results pointing to code resources or repositories.
	Code []SearchHit `json:"code,omitempty"`
	// PackageTracking holds tracking-site results for shipment numbers.
	PackageTracking []SearchHit `json:"package_tracking,omitempty"`
	// PublicRecords holds results for public records such as government
	// documents.
	PublicRecords []SearchHit `json:"public_records,omitempty"`
	// Weather holds current-weather results.
	Weather []SearchHit `json:"weather,omitempty"`
	// RelatedSearch holds queries related to the current one.
	RelatedSearch []SearchHit `json:"related_search,omitempty"`
	// Listicle holds list-style results.
	Listicle []SearchHit `json:"listicle,omitempty"`
	// WebArchive holds archived-website results.
	WebArchive []SearchHit `json:"web_archive,omitempty"`
}

SearchData groups search results by category. Each bucket holds zero or more SearchHit entries with category-specific extra data exposed via [SearchHit.Props].

type SearchExtract

type SearchExtract struct {
	// Count is the number of top results to extract content from. Valid
	// range is 1..10 server-side.
	Count int `json:"count,omitempty"`
	// Timeout is a per-page extraction time budget in seconds, independent
	// of the top-level search timeout. Valid range is 0.5..4 server-side.
	Timeout float64 `json:"timeout,omitempty"`
}

SearchExtract configures optional in-line page content extraction for search results. When set, the server extracts content from the top results and embeds it into each result's snippet.

type SearchFilters

type SearchFilters struct {
	// Region filters results to an ISO-3166-1 alpha-2 country code.
	Region string `json:"region,omitempty"`
	// After filters to results published or updated on or after this date
	// (YYYY-MM-DD).
	After string `json:"after,omitempty"`
	// Before filters to results published or updated on or before this date
	// (YYYY-MM-DD).
	Before string `json:"before,omitempty"`
}

SearchFilters applies coarse-grained filters to search results. Fields here take priority over equivalent fields on Lens.

type SearchHit

type SearchHit struct {
	// URL is the direct URL of the matched resource.
	URL string `json:"url"`
	// Title is the resource title. For HTML pages this reflects the
	// document's <title>; for videos it's the display title on the source
	// site.
	Title string `json:"title"`
	// Snippet is a short summary of the resource. When in-line extraction
	// was requested via [SearchRequest.Extract], this field is replaced
	// with the extracted page markdown.
	Snippet string `json:"snippet,omitempty"`
	// Time is the resource's creation or last-updated timestamp as
	// returned by the server (typically an RFC-3339 string).
	Time string `json:"time,omitempty"`
	// Image is the cover image or video thumbnail for the resource, when
	// available.
	Image *Image `json:"image,omitempty"`
	// Props is a category-specific bag of additional metadata. Its shape
	// varies by result category (for example, "question" on
	// AdjacentQuestion hits, "paywalled" on Search hits). Decode with
	// json.Unmarshal when needed.
	Props json.RawMessage `json:"props,omitempty"`
}

SearchHit is a single search result. The shared fields cover all result categories; category-specific extras are preserved as raw JSON in [SearchHit.Props] and can be decoded by the caller when needed.

type SearchMeta

type SearchMeta struct {
	// Trace is the request trace ID, useful when contacting Kagi support.
	Trace string `json:"trace"`
	// Node identifies the server node that fulfilled the request.
	Node string `json:"node"`
	// MS is the server-side processing time in milliseconds, excluding
	// network round-trip.
	MS int `json:"ms"`
}

SearchMeta is the meta envelope of a search response.

The exact set of fields is intended for debugging and may evolve over time; callers should treat it as advisory and avoid building hard dependencies on individual fields.

type SearchRequest

type SearchRequest struct {
	// Query is the search query to run. Required.
	Query string `json:"query"`

	// Workflow selects the category of results. Defaults to
	// [WorkflowSearch] server-side when unset.
	Workflow Workflow `json:"workflow,omitempty"`

	// LensID applies a saved or built-in lens by identifier. Accepts either
	// the bare ID portion of a lens URL (https://kagi.com/lenses/ID) or the
	// full URL.
	LensID string `json:"lens_id,omitempty"`

	// Lens describes an inline lens to apply for this request. Options
	// supplied by the lens take precedence over equivalent operators in the
	// raw query string.
	Lens *Lens `json:"lens,omitempty"`

	// Filters narrow results by region or publication date. Filters take
	// priority over equivalent fields on Lens.
	Filters *SearchFilters `json:"filters,omitempty"`

	// Extract opts in to fetching page content for the top results. Use of
	// this option incurs additional cost billed at the account's Extract
	// API rate.
	Extract *SearchExtract `json:"extract,omitempty"`

	// Personalizations applies per-request domain and regex ranking rules.
	Personalizations *Personalizations `json:"personalizations,omitempty"`

	// Page is the 1-indexed page number for paginated results. Valid range
	// is 1..10 server-side.
	Page int `json:"page,omitempty"`

	// Limit caps the number of results returned. Valid range is 1..1024
	// server-side. Note: this only limits what is returned, it does not
	// reduce the amount of work the server does.
	Limit int `json:"limit,omitempty"`

	// Timeout is the server-side time budget for collecting results, in
	// seconds. Valid range is 0.5..4 server-side.
	Timeout float64 `json:"timeout,omitempty"`

	// SafeSearch toggles filtering of potentially NSFW content. The server
	// default is true; leave nil to inherit it, or set explicitly to
	// override.
	SafeSearch *bool `json:"safe_search,omitempty"`
}

SearchRequest is the input to Client.Search.

Only [SearchRequest.Query] is required; all other fields are optional and are omitted from the request body when left at their zero value.

type SearchResult

type SearchResult struct {
	// Meta carries trace and timing information about the request.
	Meta SearchMeta
	// Data carries result buckets, grouped by category. Any bucket may be
	// absent or empty for a given query.
	Data SearchData
}

SearchResult is the response returned by Client.Search.

type TimeRelative

type TimeRelative string

TimeRelative restricts results to pages updated within a recent window.

const (
	TimeRelativeDay   TimeRelative = "day"
	TimeRelativeWeek  TimeRelative = "week"
	TimeRelativeMonth TimeRelative = "month"
)

Supported TimeRelative values.

type Workflow

type Workflow string

Workflow selects which class of results the Search endpoint should return.

const (
	WorkflowSearch   Workflow = "search"
	WorkflowImages   Workflow = "images"
	WorkflowVideos   Workflow = "videos"
	WorkflowNews     Workflow = "news"
	WorkflowPodcasts Workflow = "podcasts"
)

Supported Workflow values.

Directories

Path Synopsis
_examples
custom-client command
Custom-client example: compose NewClient with every supported Option, including a caller-supplied *http.Client.
Custom-client example: compose NewClient with every supported Option, including a caller-supplied *http.Client.
extract command
Minimal Extract example.
Minimal Extract example.
search command
Minimal Search example.
Minimal Search example.
search-advanced command
Advanced Search example: inline lens, filters, time window, per-request domain ranking, and in-line page extraction for the top results.
Advanced Search example: inline lens, filters, time window, per-request domain ranking, and in-line page extraction for the top results.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL