Skip to content

LearnTutorials

Add cited web research to your app with Exa Agent

Send a research question to Exa Agent from a Node.js script and get back a cited answer and structured JSON for your app, in 20 minutes.

By Recaply EditorsAdvanced20 min5 stepsUpdated

A magnifying glass rests on a stack of paper cards held together with paper clips

What you need

  1. Step 1: Get an API key

    2 min

    Every request to Exa is signed with your key, and new accounts come with free monthly credits.

    1. Go to dashboard.exa.ai/api-keys and sign up or sign in.
    2. Create a new API key and copy it.
    3. Want to see a run first? Try a question in the Agent playground.

    You should see your new key in the list of API keys.

    Treat the key like a password. Keep it out of your code, chat logs and any file you commit or share.

  2. Step 2: Set up a project

    3 min

    The exa-js package wraps the API, and it reads your key from the environment.

    1. In a terminal, run the commands below to make a folder and install the package.
    2. The last line sets your key for this window. On Windows, run setx EXA_API_KEY "[YOUR API KEY]" and open a new window.
    Run this
    mkdir exa-research && cd exa-research
    npm init -y
    npm install exa-js
    export EXA_API_KEY="[YOUR API KEY]"

    You should see exa-js listed under dependencies in package.json.

    Later, the script says the API key is missing?

    export only lasts in the window where you ran it, and setx only reaches new windows. Set the key again in the window you run the script from.

  3. Step 3: Run your first research task

    5 min

    Exa Agent searches, reads and checks pages for you, then returns one answer with its sources.

    1. Save the code below as research.mjs in the folder. Put your own question in the query.
    2. Run node research.mjs and wait. Runs aren't instant, because the agent searches and reads many pages first.
    Your script
    import Exa from "exa-js";
    
    const exa = new Exa();
    const run = await exa.agent.runs.create({
      query: "[YOUR RESEARCH QUESTION]",
      effort: "medium"
    });
    const done = await exa.agent.runs.pollUntilFinished(run.id, { pollInterval: 4000 });
    
    if (done.status !== "completed") {
      console.log(done.status, done.error?.message);
    } else {
      console.log(done.output.text);
      for (const entry of done.output.grounding ?? []) {
        for (const source of entry.citations) console.log("-", source.title, source.url);
      }
      console.log("Cost: $" + done.costDollars?.total);
    }

    You should see a written answer, then a list of source titles and links, then the run's cost.

    Node says you can't use import outside a module?

    Check that the file name ends in .mjs, not .js. Or add "type": "module" to package.json.

    medium costs $0.10 a run and suits most questions. Use low, at $0.025, for quick lookups, or high, at $0.50, for harder research.

  4. Step 4: Get structured JSON back

    5 min

    A schema tells the agent exactly which fields to fill, so your app can use the result without parsing text.

    1. In research.mjs, replace the exa.agent.runs.create call with the one below.
    2. Below the line that prints done.output.text, add console.log(JSON.stringify(done.output.structured, null, 2));.
    3. Run node research.mjs again.
    Your request
    const run = await exa.agent.runs.create({
      query: "Find 5 open-source tools for [YOUR TOPIC] launched this year.",
      effort: "medium",
      outputSchema: {
        type: "object",
        properties: {
          tools: {
            type: "array",
            maxItems: 5,
            items: {
              type: "object",
              properties: {
                name: { type: "string" },
                website: { type: "string", format: "uri" },
                what_it_does: { type: "string" }
              },
              required: ["name", "website", "what_it_does"]
            }
          }
        },
        required: ["tools"]
      }
    });

    You should see a JSON object with a tools list, each with a name, a website and a line on what it does.

    The run fails with INVALID_OUTPUT_SCHEMA?

    Exa turns down a schema that no answer could match. Check that every name in a required list also appears in properties.

    Set maxItems on each list to cap how many items come back.

  5. Step 5: Pass the research to your model

    5 min

    The answer and its links give your chatbot current facts to work from, with sources it can cite.

    1. Take done.output.text and the source links from your script.
    2. Put them in your model's prompt above the user's question, as in the template below.
    3. For a follow-up, start a new run and pass the old run's ID as previousRunId.
    Your prompt template
    Answer the question using only the research below. Put the source link after each fact. If the research doesn't cover something, say so.
    
    Research:
    [OUTPUT TEXT]
    
    Sources:
    [SOURCE LINKS]
    
    Question: [USER QUESTION]

    You should see an answer from your model that cites the links Exa found.

    The model adds facts that aren't in the research?

    Keep the rule to use only the research at the very top of the prompt. Ask it to say plainly when something isn't covered.

You get

A Node.js script that sends a question to Exa Agent and gets back a cited answer, structured JSON and the cost of each run

Did this guide work for you?

Sources