> ## Documentation Index
> Fetch the complete documentation index at: https://hyperbrowser.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Jev Computer Use

> Automate browser tasks with Jev's TypeSafe decision models

Jev Computer Use is a native CDP browser agent. It observes the current page, chooses one operation and target, then executes that action. Jev works from page text and DOM controls rather than screenshots.

Hyperbrowser runs Jev tasks in managed cloud browsers. Start a task with a single API call, then poll for results or use our SDK's blocking methods that handle everything automatically.

You can view your Jev tasks in the [dashboard](https://app.hyperbrowser.ai/features/agents/jev).

## How It Works

You can use Jev in two ways:

1. **Start and Wait**: SDKs provide a `startAndWait()` method that blocks until the task completes and returns the result
2. **Async Pattern**: Start a task, get a job ID, then poll for status and results—useful for long-running tasks or when you want more control

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @hyperbrowser/sdk dotenv
  ```

  ```bash yarn theme={null}
  yarn add @hyperbrowser/sdk dotenv
  ```

  ```bash pip theme={null}
  pip install hyperbrowser python-dotenv
  ```

  ```bash uv theme={null}
  uv add hyperbrowser python-dotenv
  ```
</CodeGroup>

## Quick Start

The simplest way to run a Jev task is with the `startAndWait()` method, which handles everything for you:

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";
  import { config } from "dotenv";

  config();

  const client = new Hyperbrowser({
    apiKey: process.env.HYPERBROWSER_API_KEY,
  });

  async function main() {
    const result = await client.agents.jevComputerUse.startAndWait({
      task: "Go to Hacker News and tell me the title of the top post",
      maxSteps: 20,
    });

    console.log(`Output:\n${result.data?.finalResult}`);
  }

  main().catch((err) => {
    console.error(`Error: ${err.message}`);
  });
  ```

  ```python Python 1.0+ theme={null}
  from hyperbrowser import Hyperbrowser
  import os
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))

  result = client.agents.jev_computer_use.start_and_wait(
      params={
          "task": "Go to Hacker News and tell me the title of the top post",
          "max_steps": 20,
      }
  )

  print(f"Output:\n{result.data.final_result}")
  ```

  ```python Python (legacy) theme={null}
  from hyperbrowser import Hyperbrowser
  from hyperbrowser.models import StartJevComputerUseTaskParams
  import os
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))

  result = client.agents.jev_computer_use.start_and_wait(
      params=StartJevComputerUseTaskParams(
          task="Go to Hacker News and tell me the title of the top post", max_steps=20
      )
  )

  print(f"Output:\n{result.data.final_result}")
  ```

  ```bash cURL theme={null}
  # Start the task
  curl -X POST https://api.hyperbrowser.ai/api/task/jev \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "task": "Go to Hacker News and tell me the title of the top post",
      "maxSteps": 20
    }'

  # Response: {"jobId": "abc123", "liveUrl": "https://..."}

  # Check status
  curl https://api.hyperbrowser.ai/api/task/jev/abc123/status \
    -H "x-api-key: YOUR_API_KEY"

  # Get full results
  curl https://api.hyperbrowser.ai/api/task/jev/abc123 \
    -H "x-api-key: YOUR_API_KEY"
  ```
</CodeGroup>

## Async Pattern

When you need more control, use the async pattern to start a task and poll for results:

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";
  import { config } from "dotenv";

  config();

  const client = new Hyperbrowser({
    apiKey: process.env.HYPERBROWSER_API_KEY,
  });

  async function main() {
    try {
      // Start the task
      const task = await client.agents.jevComputerUse.start({
        task: "What is the title of the first post on Hacker News today?",
        maxSteps: 20,
      });

      console.log(`Task started: ${task.jobId}`);
      console.log(`Watch live: ${task.liveUrl}`);

      // Poll for completion
      let result;
      while (true) {
        result = await client.agents.jevComputerUse.getStatus(task.jobId);
        console.log(`Status: ${result.status}`);

        if (result.status === "completed" || result.status === "failed") {
          break;
        }

        await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait 5s
      }

      const fullResult = await client.agents.jevComputerUse.get(task.jobId);

      if (fullResult.status === "completed") {
        console.log("Result:", fullResult.data?.finalResult);
        console.log("Steps taken:", fullResult.data?.steps?.length);
      } else {
        console.error("Task failed:", fullResult.error);
      }
    } catch (err) {
      console.error(`Error: ${err.message}`);
    }
  }

  main();
  ```

  ```python Python 1.0+ theme={null}
  import asyncio
  from hyperbrowser import AsyncHyperbrowser
  from dotenv import load_dotenv
  import os

  load_dotenv()

  client = AsyncHyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  async def main():
      try:
          # Start the task
          task = await client.agents.jev_computer_use.start(
              params={
                  "task": "What is the title of the first post on Hacker News today?",
                  "max_steps": 20,
              }
          )

          print(f"Task started: {task.job_id}")
          print(f"Watch live: {task.live_url}")

          # Poll for completion
          while True:
              result = await client.agents.jev_computer_use.get_status(task.job_id)
              print(f"Status: {result.status}")

              if result.status in ["completed", "failed"]:
                  break

              await asyncio.sleep(5)  # Wait 5s

          full_result = await client.agents.jev_computer_use.get(task.job_id)

          if full_result.status == "completed":
              print("Result:", full_result.data.final_result)
              print(
                  "Steps taken:",
                  len(full_result.data.steps) if full_result.data.steps else 0,
              )
          else:
              print("Task failed:", full_result.error)
      except Exception as e:
          print(f"Error: {e}")


  if __name__ == "__main__":
      asyncio.run(main())
  ```

  ```python Python (legacy) theme={null}
  import asyncio
  from hyperbrowser import AsyncHyperbrowser
  from hyperbrowser.models import StartJevComputerUseTaskParams
  from dotenv import load_dotenv
  import os

  load_dotenv()

  client = AsyncHyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  async def main():
      try:
          # Start the task
          task = await client.agents.jev_computer_use.start(
              params=StartJevComputerUseTaskParams(
                  task="What is the title of the first post on Hacker News today?",
                  max_steps=20,
              )
          )

          print(f"Task started: {task.job_id}")
          print(f"Watch live: {task.live_url}")

          # Poll for completion
          while True:
              result = await client.agents.jev_computer_use.get_status(task.job_id)
              print(f"Status: {result.status}")

              if result.status in ["completed", "failed"]:
                  break

              await asyncio.sleep(5)  # Wait 5s

          full_result = await client.agents.jev_computer_use.get(task.job_id)

          if full_result.status == "completed":
              print("Result:", full_result.data.final_result)
              print(
                  "Steps taken:",
                  len(full_result.data.steps) if full_result.data.steps else 0,
              )
          else:
              print("Task failed:", full_result.error)
      except Exception as e:
          print(f"Error: {e}")


  if __name__ == "__main__":
      asyncio.run(main())
  ```
</CodeGroup>

## Stop a Running Task

Stop a task before it completes:

<CodeGroup>
  ```typescript Node.js theme={null}
  await client.agents.jevComputerUse.stop("job-id");
  ```

  ```python Python theme={null}
  client.agents.jev_computer_use.stop("job-id")
  ```

  ```bash cURL theme={null}
  curl -X PUT https://api.hyperbrowser.ai/api/task/jev/job-id/stop \
    -H "x-api-key: YOUR_API_KEY"
  ```
</CodeGroup>

## Parameters

<ParamField path="task" type="string" required>
  Natural language description of what you want Jev to accomplish. Be specific for best results. The task must be at most 8000 UTF-8 bytes.
</ParamField>

<ParamField path="llm" type="string" default="jev-1.13.0">
  Jev decision model to use. Available options:

  * `"jev-1.13.0"` - Pinned Jev 1.13.0 decision model (default)
  * `"jev-latest"` - Latest hosted Jev decision model
</ParamField>

<ParamField path="textLlm" type="string" default="gemini-3.5-flash-lite">
  Text helper model used for field values and the final result. Currently `"gemini-3.5-flash-lite"` is the only supported option.
</ParamField>

<ParamField path="maxSteps" type="number" default="100">
  Maximum number of executed policy actions. Allowed range is 1-300.
</ParamField>

<ParamField path="maxFailures" type="number" default="3">
  Accepted for compatibility with other agents. Jev does not add controller-level retries from this value.
</ParamField>

<ParamField path="sessionId" type="string">
  ID of an existing browser session to reuse. Useful for multi-step workflows that need to maintain the same browser session.
</ParamField>

<ParamField path="keepBrowserOpen" type="boolean" default="false">
  Keep the browser session alive after task completion.
</ParamField>

<ParamField path="sessionOptions" type="object">
  [Session configuration](/docs/api-reference/start-a-jev-computer-use-task#body-session-options) (proxy, stealth, captcha solving, etc.). Only applies when creating a new session. If you provide an existing `sessionId`, these options are ignored.
</ParamField>

<ParamField path="useCustomApiKeys" type="boolean" default="false">
  Use your own Jev and Google API keys instead of consuming Hyperbrowser credits for model calls. You will only be charged for browser usage.
</ParamField>

<ParamField path="apiKeys" type="object">
  API keys for `jev` and `google`. Both are required when `useCustomApiKeys` is `true`.

  ```typescript theme={null}
  {
    jev: "...",
    google: "..."
  }
  ```
</ParamField>

<Tip>
  The agent may not complete the task within the specified `maxSteps`. If that happens, try increasing the `maxSteps` parameter.

  Additionally, the browser session used by the AI Agent will time out based on your team's default Session Timeout settings or the session's `timeoutMinutes` parameter if provided. You can adjust the default Session Timeout in the [Settings page](https://app.hyperbrowser.ai/settings).
</Tip>

<Note>
  Jev does not send screenshots to either model. It reads visible page text and common HTML/ARIA controls, then dispatches native CDP clicks, typing, and selects.
</Note>

## Reuse Browser Sessions

You can pass in an existing `sessionId` to the Jev task so that it can execute the task on an existing session. Also, if you want to keep the session open after executing the task, you can supply the `keepBrowserOpen` parameter.

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";
  import { config } from "dotenv";

  config();

  const client = new Hyperbrowser({
    apiKey: process.env.HYPERBROWSER_API_KEY,
  });

  const main = async () => {
    const session = await client.sessions.create();

    try {
      const result = await client.agents.jevComputerUse.startAndWait({
        task: "What is the title of the first post on Hacker News today?",
        sessionId: session.id,
        keepBrowserOpen: true,
      });

      console.log(`Output:\n${result.data?.finalResult}`);

      const result2 = await client.agents.jevComputerUse.startAndWait({
        task: "Tell me how many upvotes the first post has.",
        sessionId: session.id,
      });

      console.log(`\nOutput:\n${result2.data?.finalResult}`);
    } catch (err) {
      console.error(`Error: ${err}`);
    } finally {
      await client.sessions.stop(session.id);
    }
  };

  main().catch((err) => {
    console.error(`Error: ${err.message}`);
  });
  ```

  ```python Python 1.0+ theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      session = client.sessions.create()

      try:
          resp = client.agents.jev_computer_use.start_and_wait(
              {
                  "task": "What is the title of the first post on Hacker News today?",
                  "session_id": session.id,
                  "keep_browser_open": True,
              }
          )

          print(f"Output:\n{resp.data.final_result}")

          resp2 = client.agents.jev_computer_use.start_and_wait(
              {
                  "task": "Tell me how many upvotes the first post has.",
                  "session_id": session.id,
              }
          )

          print(f"\nOutput:\n{resp2.data.final_result}")
      finally:
          client.sessions.stop(session.id)


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```

  ```python Python (legacy) theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from hyperbrowser.models import StartJevComputerUseTaskParams
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      session = client.sessions.create()

      try:
          resp = client.agents.jev_computer_use.start_and_wait(
              StartJevComputerUseTaskParams(
                  task="What is the title of the first post on Hacker News today?",
                  session_id=session.id,
                  keep_browser_open=True,
              )
          )

          print(f"Output:\n{resp.data.final_result}")

          resp2 = client.agents.jev_computer_use.start_and_wait(
              StartJevComputerUseTaskParams(
                  task="Tell me how many upvotes the first post has.",
                  session_id=session.id,
              )
          )

          print(f"\nOutput:\n{resp2.data.final_result}")
      finally:
          client.sessions.stop(session.id)


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```
</CodeGroup>

<Warning>
  Always set `keepBrowserOpen: true` on tasks that you want to reuse the session from. Otherwise, the session will be automatically closed when the task completes.
</Warning>

## Using Your Own API Keys

Bring your own Jev and Google API keys to avoid consuming Hyperbrowser credits for model calls. You'll still be charged for browser session usage, but save on token costs. Jev BYOK requires both keys: `jev` for decisions and `google` for text generation.

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";
  import { config } from "dotenv";

  config();

  const client = new Hyperbrowser({
    apiKey: process.env.HYPERBROWSER_API_KEY,
  });

  const main = async () => {
    const result = await client.agents.jevComputerUse.startAndWait({
      task: "What is the title of the first post on Hacker News today?",
      useCustomApiKeys: true,
      apiKeys: {
        jev: "<JEV_API_KEY>",
        google: "<GOOGLE_API_KEY>",
      },
    });

    console.log(`Output:\n\n${result.data?.finalResult}`);
  };

  main().catch((err) => {
    console.error(`Error: ${err.message}`);
  });
  ```

  ```python Python 1.0+ theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      resp = client.agents.jev_computer_use.start_and_wait(
          {
              "task": "What is the title of the first post on HackerNews today?",
              "use_custom_api_keys": True,
              "api_keys": {
                  "jev": "<JEV_API_KEY>",
                  "google": "<GOOGLE_API_KEY>",
              },
          }
      )

      print(f"Output:\n\n{resp.data.final_result}")


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```

  ```python Python (legacy) theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from hyperbrowser.models import StartJevComputerUseTaskParams, JevComputerUseApiKeys
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      resp = client.agents.jev_computer_use.start_and_wait(
          StartJevComputerUseTaskParams(
              task="What is the title of the first post on HackerNews today?",
              use_custom_api_keys=True,
              api_keys=JevComputerUseApiKeys(
                  jev="<JEV_API_KEY>",
                  google="<GOOGLE_API_KEY>",
              ),
          )
      )

      print(f"Output:\n\n{resp.data.final_result}")


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/task/jev \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_HYPERBROWSER_API_KEY" \
    -d '{
      "task": "What is the title of the first post on Hacker News today?",
      "useCustomApiKeys": true,
      "apiKeys": {
        "jev": "YOUR_JEV_API_KEY",
        "google": "YOUR_GOOGLE_API_KEY"
      }
    }'
  ```
</CodeGroup>

## Session Configuration

Customize the browser session used by Jev with session options.

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";
  import { config } from "dotenv";

  config();

  const client = new Hyperbrowser({
    apiKey: process.env.HYPERBROWSER_API_KEY,
  });

  const main = async () => {
    const result = await client.agents.jevComputerUse.startAndWait({
      task: "What is the title of the first post on Hacker News today?",
      sessionOptions: {
        acceptCookies: true,
      }
    });

    console.log(`Output:\n\n${result.data?.finalResult}`);
  };

  main().catch((err) => {
    console.error(`Error: ${err.message}`);
  });
  ```

  ```python Python 1.0+ theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      resp = client.agents.jev_computer_use.start_and_wait(
          {
              "task": "What is the title of the first post on Hacker News today?",
              "session_options": {
                  "accept_cookies": True,
              },
          }
      )

      print(f"Output:\n\n{resp.data.final_result}")


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```

  ```python Python (legacy) theme={null}
  import os
  from hyperbrowser import Hyperbrowser
  from hyperbrowser.models import StartJevComputerUseTaskParams, CreateSessionParams
  from dotenv import load_dotenv

  load_dotenv()

  client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))


  def main():
      resp = client.agents.jev_computer_use.start_and_wait(
          StartJevComputerUseTaskParams(
              task="What is the title of the first post on Hacker News today?",
              session_options=CreateSessionParams(
                  accept_cookies=True,
              ),
          )
      )

      print(f"Output:\n\n{resp.data.final_result}")


  if __name__ == "__main__":
      try:
          main()
      except Exception as e:
          print(f"Error: {e}")
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/task/jev \
    -H 'Content-Type: application/json' \
    -H 'x-api-key: <YOUR_API_KEY>' \
    -d '{
        "task": "What is the title of the first post on Hacker News today?",
        "sessionOptions": {
            "acceptCookies": true
        }
    }'
  ```
</CodeGroup>

<Note>
  `sessionOptions` only applies when creating a new session. If you provide a `sessionId`, these options are ignored.
</Note>

<Warning>
  Proxies and CAPTCHA solving add latency to page navigation. Only enable them when necessary for your use case.
</Warning>

## Best Practices

<AccordionGroup>
  <Accordion title="Write clear, specific task descriptions">
    Be explicit about what you want Jev to do. Instead of "check the website", say "go to example.com, find the pricing page, and extract the cost of the Enterprise plan".
  </Accordion>

  <Accordion title="Set appropriate maxSteps">
    Simple tasks often finish in well under the default of 100 steps. Complex multi-page workflows can use up to 300. Monitor failed tasks and adjust accordingly.
  </Accordion>

  <Accordion title="Reuse sessions for multi-step workflows">
    It is usually better to split up complex tasks into smaller, more manageable ones and execute them as separate agent calls on the same session.
  </Accordion>
</AccordionGroup>
