DEV Community

HaiboLi
HaiboLi

Posted on

Search Google from Java in 15 Lines (No SDK, No Pain) — A SerpApi Quickstart

A SerpApi Java quickstart I built while exploring how cleanly structured search data drops into a Java app. If you write Java and ever needed Google results as JSON, this is for you.

Why this exists

You can scrape Google yourself, but then you own: proxy rotation, CAPTCHA solving, HTML parsing that breaks every time Google changes a class name. SerpApi wraps all of that behind one REST call and hands you structured JSON.

I wanted a version that:

  • runs on any JDK 8+ (no JDK 11/21 requirement — works even on older corporate JDKs),
  • has zero framework magic — just HttpURLConnection + Gson,
  • you can read top-to-bottom in one sitting.

The whole thing

package com.example.serpapi;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public class QuickStart {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("SERPAPI_KEY");
        if (apiKey == null || apiKey.trim().isEmpty()) {
            System.err.println("ERROR: set SERPAPI_KEY first");
            System.exit(1);
        }

        String query = "best coffee in Austin";
        String urlStr = "https://serpapi.com/search.json"
                + "?engine=google"
                + "&q=" + URLEncoder.encode(query, "UTF-8")
                + "&hl=en&gl=us"
                + "&api_key=" + URLEncoder.encode(apiKey, "UTF-8");

        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "application/json");
        conn.setConnectTimeout(15000);
        conn.setReadTimeout(15000);

        int status = conn.getResponseCode();
        InputStream stream = (status >= 200 && status < 300)
                ? conn.getInputStream() : conn.getErrorStream();
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(stream, StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) sb.append(line);
        reader.close();
        conn.disconnect();

        if (status != 200) {
            System.err.println("request failed, HTTP " + status);
            System.err.println(sb);
            System.exit(1);
        }

        JsonObject data = new Gson().fromJson(sb.toString(), JsonObject.class);
        System.out.println("status: "
                + data.getAsJsonObject("search_metadata").get("status").getAsString());

        JsonArray organic = data.getAsJsonArray("organic_results");
        int limit = Math.min(3, organic.size());
        for (int i = 0; i < limit; i++) {
            JsonObject r = organic.get(i).getAsJsonObject();
            System.out.println((i + 1) + ". " + r.get("title").getAsString());
            if (r.has("link")) System.out.println("   " + r.get("link").getAsString());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

That's it. One GET, structured JSON, zero HTML parsing.

Run it

export SERPAPI_KEY="your_free_key"   # free tier: 250 searches/month, no card
mvn compile exec:java -Dexec.mainClass=com.example.serpapi.QuickStart
Enter fullscreen mode Exit fullscreen mode

Expected:

status: Success
1. The Best Coffee in Austin - Eater Austin
   https://austin.eater.com/maps/best-coffee-austin-cafes-espressos-lattes
2. Best Coffee : r/austinfood
   https://www.reddit.com/r/austinfood/comments/1ltcz3j/best_coffee/
3. a few of the best Austin coffee shops I love (both old and ...
   https://www.instagram.com/p/DbI3IQ4jjKa/?hl=en
Enter fullscreen mode Exit fullscreen mode

Prefer the official SDK? (JDK 21)

<repositories>
  <repository><id>jitpack.io</id><url>https://jitpack.io</url></repository>
</repositories>
Enter fullscreen mode Exit fullscreen mode
Map<String,String> auth = Map.of("api_key", System.getenv("SERPAPI_KEY"));
SerpApi client = new SerpApi(auth);
Map<String,String> p = Map.of("engine","google","q","best coffee in Austin","hl","en","gl","us");
JsonObject results = client.search(p);
Enter fullscreen mode Exit fullscreen mode

What I'd build next

Because the response is structured, wiring it into a real app is trivial:

  • cache search_metadata.search_id and replay via the Search Archive API,
  • push organic_results into a LLM tool-call so an agent "searches the web" with cited sources,
  • swap engine=googlebing / baidu for multi-engine comparison.

Links

Happy coding. ☕

Top comments (0)