Using Ollama Web Search API in Go

Published: (December 5, 2025 at 12:40 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Cover image for Using Ollama Web Search API in Go

Getting Started

Does Ollama have an official Go library for web search?
Ollama provides a REST API for web search that works with any Go HTTP client. While there’s no official Go SDK for web search yet, you can easily implement the API calls using the standard library.

  1. Create an API key from your Ollama account.
  2. Set the API key as an environment variable.
export OLLAMA_API_KEY="your_api_key"

On Windows PowerShell:

$env:OLLAMA_API_KEY = "your_api_key"

For a comprehensive reference on Ollama commands and usage, see the Ollama cheatsheet.

Project Setup

Create a new Go module:

mkdir ollama-search
cd ollama-search
go mod init ollama-search

How do I authenticate with Ollama’s web search API in Go?
Set the Authorization header with your API key as a Bearer token.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// Request/Response types for web_search
type WebSearchRequest struct {
	Query      string `json:"query"`
	MaxResults int    `json:"max_results,omitempty"`
}

type WebSearchResult struct {
	Title   string `json:"title"`
	URL     string `json:"url"`
	Content string `json:"content"`
}

type WebSearchResponse struct {
	Results []WebSearchResult `json:"results"`
}

func webSearch(query string, maxResults int) (*WebSearchResponse, error) {
	apiKey := os.Getenv("OLLAMA_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
	}

	reqBody := WebSearchRequest{
		Query:      query,
		MaxResults: maxResults,
	}
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequest("POST", "https://ollama.com/api/web_search", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response: %w", err)
	}

	var searchResp WebSearchResponse
	if err := json.Unmarshal(body, &searchResp); err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}
	return &searchResp, nil
}

func truncate(s string, maxLen int) string {
	if len(s) = 5 {
			fmt.Printf("  ... and %d more\n", len(result.Links)-5)
			break
		}
		fmt.Printf("  - %s\n", link)
	}
}

Reusable Client Package

Create a reusable Ollama client package for cleaner code.

// ollama/client.go
package ollama

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

type Client struct {
	apiKey     string
	httpClient *http.Client
	baseURL    string
}

func NewClient() (*Client, error) {
	apiKey := os.Getenv("OLLAMA_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
	}
	return &Client{
		apiKey: apiKey,
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
		baseURL: "https://ollama.com/api",
	}, nil
}

// Generic POST helper
func (c *Client) post(endpoint string, payload interface{}, out interface{}) error {
	jsonData, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("marshal error: %w", err)
	}
	req, err := http.NewRequest("POST", c.baseURL+endpoint, bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("request creation error: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+c.apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("request error: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
	}
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("read error: %w", err)
	}
	if err := json.Unmarshal(body, out); err != nil {
		return fmt.Errorf("unmarshal error: %w", err)
	}
	return nil
}

// WebSearch calls the /web_search endpoint
func (c *Client) WebSearch(query string, maxResults int) (*WebSearchResponse, error) {
	req := WebSearchRequest{
		Query:      query,
		MaxResults: maxResults,
	}
	var resp WebSearchResponse
	if err := c.post("/web_search", req, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

// WebFetch calls the /web_fetch endpoint
func (c *Client) WebFetch(url string) (*WebFetchResponse, error) {
	req := WebFetchRequest{URL: url}
	var resp WebFetchResponse
	if err := c.post("/web_fetch", req, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

You can now use the client in your applications:

package main

import (
	"fmt"
	"log"

	"yourmodule/ollama"
)

func main() {
	client, err := ollama.NewClient()
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Example: web search
	searchRes, err := client.WebSearch("Ollama Go SDK", 3)
	if err != nil {
		log.Fatalf("Search error: %v", err)
	}
	for _, r := range searchRes.Results {
		fmt.Printf("- %s (%s)\n", r.Title, r.URL)
	}

	// Example: fetch a page
	fetchRes, err := client.WebFetch("https://ollama.com")
	if err != nil {
		log.Fatalf("Fetch error: %v", err)
	}
	fmt.Printf("\nFetched title: %s\n", fetchRes.Title)
}
Back to Blog

Related posts

Read more »