Skip to main content
Custom actions let you extend HyperAgent’s capabilities beyond browser automation. Add integrations with external APIs, databases, or any custom logic.

Defining a Custom Action

A custom action requires three things:
  1. type: A descriptive name for the action
  2. actionParams: A Zod schema describing the parameters
  3. run: A function that executes the action
import { HyperAgent, AgentActionDefinition, ActionContext, ActionOutput } from "@hyperbrowser/agent";
import { z } from "zod";

const SendEmailAction: AgentActionDefinition = {
  type: "send_email",
  actionParams: z.object({
    to: z.string().describe("Email recipient address"),
    subject: z.string().describe("Email subject line"),
    body: z.string().describe("Email body content"),
  }).describe("Send an email to a specified recipient"),
  
  run: async function(
    ctx: ActionContext,
    params: { to: string; subject: string; body: string }
  ): Promise<ActionOutput> {
    // Your email sending logic here
    await sendEmail(params.to, params.subject, params.body);
    
    return {
      success: true,
      message: `Successfully sent email to ${params.to}`,
    };
  },
};

Using Custom Actions

Pass custom actions when creating the agent:
const agent = new HyperAgent({
  customActions: [SendEmailAction],
});

const result = await agent.executeTask(
  "Go to my inbox, find the latest newsletter, summarize it, and send the summary to [email protected]"
);
The AI will automatically use your custom action when appropriate. Integrate with a search API like Exa:
import Exa from "exa-js";

const exaClient = new Exa(process.env.EXA_API_KEY);

const WebSearchAction: AgentActionDefinition = {
  type: "web_search",
  actionParams: z.object({
    query: z.string().describe("Search query - keep it concise and specific"),
  }).describe("Search the web and return relevant results"),
  
  run: async function(ctx, params): Promise<ActionOutput> {
    const results = await exaClient.search(params.query, {
      numResults: 5,
    });
    
    const formatted = results.results
      .map(r => `- ${r.title}: ${r.url}`)
      .join("\n");
    
    return {
      success: true,
      message: `Search results for "${params.query}":\n${formatted}`,
    };
  },
};

const agent = new HyperAgent({
  customActions: [WebSearchAction],
});

await agent.executeTask(
  "Search for the latest news about AI and summarize the top 3 stories"
);

Action Context

The ActionContext provides access to:
interface ActionContext {
  page: Page;           // Current Playwright page
  agent: HyperAgent;    // Agent instance
  taskId: string;       // Current task ID
}
Use it to interact with the browser or agent state:
const SaveScreenshotAction: AgentActionDefinition = {
  type: "save_screenshot",
  actionParams: z.object({
    filename: z.string().describe("Filename to save the screenshot as"),
  }),
  
  run: async function(ctx, params): Promise<ActionOutput> {
    await ctx.page.screenshot({ path: params.filename });
    
    return {
      success: true,
      message: `Screenshot saved to ${params.filename}`,
    };
  },
};

Action Output

Return an ActionOutput object:
interface ActionOutput {
  success: boolean;  // Whether the action succeeded
  message: string;   // Result message shown to the AI
}
The message helps the AI understand what happened and plan next steps.

Multiple Custom Actions

Combine multiple actions for complex workflows:
const agent = new HyperAgent({
  customActions: [
    WebSearchAction,
    SendEmailAction,
    SaveToNotionAction,
    SlackNotifyAction,
  ],
});

await agent.executeTask(
  "Research competitors, save findings to Notion, and notify the team on Slack"
);

Next Steps