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

# Quickstart

> Install Libretto and run your first workflow end to end.

## Agent prompt

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
Fetch and follow https://libretto.sh/start.md to set up Libretto and create a new browser automation.
```

## Manual

Install Libretto into the Node.js package that contains your browser automations. Run Libretto commands with `npx libretto` from that package.

<Steps>
  <Step title="Choose a setup path">
    Decide whether you want to create a new Libretto package or add Libretto to an existing Node.js package.

    If you create a new package, choose where it should live and what it should be named. If you use an existing package, switch into that package directory before installing Libretto.
  </Step>

  <Step title="Option A: create a new Libretto package">
    From the directory where the new package should be created:

    ```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm create libretto@latest
    ```

    You can pass a package name directly:

    ```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm create libretto@latest my-automations
    ```

    This scaffolds a package, installs dependencies, runs setup, and downloads Chromium.
  </Step>

  <Step title="Option B: add Libretto to an existing package">
    From the existing package directory, add Libretto as a dependency and run setup:

    ```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npm install libretto zod
    npx libretto setup
    ```

    Then create a workflow file and run it with `npx libretto run <path> --headless`.
  </Step>

  <Step title="Create and run a smoke workflow">
    Create `src/workflows/scrape-page.ts` in the package you set up:

    ```ts src/workflows/scrape-page.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { workflow } from "libretto";
    import { z } from "zod";

    export default workflow(
      "scrape-page",
      {
        input: z.object({}),
        output: z.object({
          title: z.string(),
        }),
      },
      async ({ page }) => {
        await page.goto("https://example.com");
        const title = await page.title();
        console.log(`Page title: ${title}`);

        return { title };
      },
    );
    ```

    Run it headless:

    ```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
    npx libretto run src/workflows/scrape-page.ts --headless
    ```

    This confirms your local setup works and shows the basic run loop.
  </Step>
</Steps>

<Card title="Next: First workflow" icon="arrow-right" href="/get-started/first-workflow">
  Expand the smoke workflow into a minimal real workflow you can iterate on.
</Card>

## Compare browser automation tools

If you are choosing between Libretto and another browser automation tool, these comparisons explain the production trade-offs:

<CardGroup cols={3}>
  <Card title="Libretto vs Browser Use" icon="browser" href="https://libretto.sh/vs/browser-use">
    Compare deterministic scripts with a runtime browser agent.
  </Card>

  <Card title="Libretto vs Stagehand" icon="wand-magic-sparkles" href="https://libretto.sh/vs/stagehand">
    Compare generated workflows with act(), observe(), and runtime inference.
  </Card>

  <Card title="Libretto vs Playwright codegen" icon="code" href="https://libretto.sh/vs/playwright-codegen">
    Compare browser recording with agent-built workflows and validation loops.
  </Card>
</CardGroup>
