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

# Interaja após o scraping

> Interaja com uma página que você obteve usando prompts ou executando código.

Faça o scraping de uma página para obter dados limpos e, em seguida, chame `/interact` para começar a realizar ações nessa página: clicar em botões, preencher formulários, extrair conteúdo dinâmico ou navegar mais profundamente. Basta descrever o que você quer, ou escrever código se precisar de controle total.

<CardGroup cols={3}>
  <Card title="Prompts de IA" icon="wand-magic-sparkles">
    Descreva a ação que você quer executar na página
  </Card>

  <Card title="Execução de código" icon="code">
    Interaja com segurança por meio da execução de código usando playwright, agent-browser
  </Card>

  <Card title="Visualização em tempo real" icon="eye">
    Assista ou interaja com o navegador em tempo real por meio de um stream incorporável
  </Card>
</CardGroup>

<div id="how-it-works">
  ## Como funciona
</div>

1. **Faça o scraping** de uma URL com `POST /v2/scrape`. A resposta inclui um `scrapeId` em `data.metadata.scrapeId`. Se você quiser persistir o estado do navegador, passe `profile` nesta solicitação.
2. **Interaja** chamando `POST /v2/scrape/{scrapeId}/interact` com um `prompt` ou com `code` do Playwright. Não passe `profile` aqui; a sessão de interação herda o perfil do job de scraping.
3. **Encerre** a sessão com `DELETE /v2/scrape/{scrapeId}/interact` quando terminar. Para perfis graváveis, as mudanças são salvas quando a sessão é encerrada.

<div id="quick-start">
  ## Início rápido
</div>

Faça o scraping de uma página, interaja com ela e encerre a sessão:

<CodeGroup>
  ```python Python theme={null}
  from firecrawl import Firecrawl

  app = Firecrawl(
    # Nenhuma API key necessária para começar — adicione uma para limites de taxa maiores:
    # api_key="fc-YOUR-API-KEY",
  )

  # 1. Fazer scraping da página inicial da Amazon
  result = app.scrape("https://www.amazon.com", formats=["markdown"])
  scrape_id = result.metadata.scrape_id

  # 2. Interagir — buscar um produto e obter seu preço
  app.interact(scrape_id, prompt="Search for iPhone 16 Pro Max")
  response = app.interact(scrape_id, prompt="Click on the first result and tell me the price")
  print(response.output)

  # 3. Encerrar a sessão
  app.stop_interaction(scrape_id)
  ```

  ```js Node theme={null}
  import { Firecrawl } from 'firecrawl';

  const app = new Firecrawl({
    // Nenhuma API key necessária para começar — adicione uma para limites de taxa mais altos:
    // apiKey: 'fc-YOUR-API-KEY',
  });

  // 1. Fazer scraping da página inicial da Amazon
  const result = await app.scrape('https://www.amazon.com', { formats: ['markdown'] });
  const scrapeId = result.metadata?.scrapeId;

  // 2. Interagir — buscar um produto e obter seu preço
  await app.interact(scrapeId, { prompt: 'Search for iPhone 16 Pro Max' });
  const response = await app.interact(scrapeId, { prompt: 'Click on the first result and tell me the price' });
  console.log(response.output);

  // 3. Encerrar a sessão
  await app.stopInteraction(scrapeId);
  ```

  ```bash cURL theme={null}
  # 1. Fazer scraping da página inicial da Amazon
  # Nenhuma API key necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa maiores:
  RESPONSE=$(curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Content-Type: application/json" \
    -d '{"url": "https://www.amazon.com", "formats": ["markdown"]}')

  SCRAPE_ID=$(echo $RESPONSE | jq -r '.data.metadata.scrapeId')

  # 2. Interagir — buscar um produto e obter seu preço
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Search for iPhone 16 Pro Max"}'

  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Click on the first result and tell me the price"}'

  # 3. Encerrar a sessão
  curl -s -X DELETE "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact"
  ```

  ```bash CLI theme={null}
  # 1. Faça scraping da página inicial da Amazon (o ID de scraping é salvo automaticamente)
  firecrawl scrape https://www.amazon.com

  # 2. Interaja — busque um produto e obtenha seu preço
  firecrawl interact "Search for iPhone 16 Pro Max"
  firecrawl interact "Click on the first result and tell me the price"

  # 3. Encerre a sessão
  firecrawl interact stop
  ```
</CodeGroup>

```json Response theme={null}
{
  "success": true,
  "cdpUrl": "wss://browser.firecrawl.dev/...",
  "liveViewUrl": "https://liveview.firecrawl.dev/...",
  "interactiveLiveViewUrl": "https://liveview.firecrawl.dev/...",
  "output": "The iPhone 16 Pro Max (256GB) is priced at $1,199.00.",
  "exitCode": 0,
  "killed": false
}
```

<div id="interact-via-prompting">
  ## Interaja usando prompts
</div>

A forma mais simples de interagir com uma página. Descreva o que você quer em linguagem natural, e ele clicará, digitará, rolará a página e extrairá dados automaticamente.

<CodeGroup>
  ```python Python theme={null}
  response = app.interact(scrape_id, prompt="What are the customer reviews saying about battery life?")
  print(response.output)
  ```

  ```js Node theme={null}
  const response = await app.interact(scrapeId, {
    prompt: 'What are the customer reviews saying about battery life?',
  });
  console.log(response.output);
  ```

  ```bash cURL theme={null}
  # Nenhuma API key necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa maiores:
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{
      "prompt": "What are the customer reviews saying about battery life?"
    }'
  ```

  ```bash CLI theme={null}
  firecrawl interact "What are the customer reviews saying about battery life?"
  ```
</CodeGroup>

A resposta inclui um campo `output` com a resposta do agente:

```json Response theme={null}
{
  "success": true,
  "cdpUrl": "wss://browser.firecrawl.dev/...",
  "liveViewUrl": "https://liveview.firecrawl.dev/...",
  "interactiveLiveViewUrl": "https://liveview.firecrawl.dev/...",
  "output": "Customers are generally positive about battery life. Most reviewers report 8-10 hours of use on a single charge. A few noted it drains faster with heavy multitasking.",
  "stdout": "...",
  "result": "...",
  "stderr": "",
  "exitCode": 0,
  "killed": false
}
```

<div id="keep-prompts-small-and-focused">
  ### Mantenha os Prompts Pequenos e Focados
</div>

Prompts funcionam melhor quando cada um é uma **tarefa única e clara**. Em vez de pedir ao agente para executar um fluxo de trabalho complexo com várias etapas de uma só vez, divida isso em chamadas `interact` separadas. Cada chamada reutiliza a mesma sessão do navegador, então o estado é mantido entre elas.

<div id="running-code">
  ## Executando código
</div>

Para ter controle total, você pode executar código diretamente no sandbox do navegador. A variável `page` (um objeto `Page` do Playwright) está disponível tanto em Node.js quanto em Python. O modo Bash vem com [agent-browser](https://github.com/vercel-labs/agent-browser) pré-instalado. Você também pode fazer capturas de tela na sessão: use `(await page.screenshot()).toString("base64")` em Node.js, `await page.screenshot(path="/tmp/screenshot.png")` em Python ou `agent-browser screenshot` no Bash.

<div id="nodejs-playwright">
  ### Node.js (Playwright)
</div>

A linguagem padrão. Escreva código Playwright diretamente. `page` já está conectado ao navegador.

<CodeGroup>
  ```python Python theme={null}
  response = app.interact(scrape_id, code="""
  // Clique em um botão e aguarde a navegação
  await page.click('#next-page');
  await page.waitForLoadState('networkidle');

  // Extraia o conteúdo da nova página
  const title = await page.title();
  const content = await page.$eval('.article-body', el => el.textContent);
  JSON.stringify({ title, content });
  """)
  print(response.result)
  ```

  ```js Node theme={null}
  const response = await app.interact(scrapeId, {
    code: `
      // Clica em um botão e aguarda a navegação
      await page.click('#next-page');
      await page.waitForLoadState('networkidle');

      // Extrai o conteúdo da nova página
      const title = await page.title();
      const content = await page.$eval('.article-body', el => el.textContent);
      JSON.stringify({ title, content });
    `,
  });
  console.log(response.result);
  ```

  ```bash cURL theme={null}
  # Nenhuma chave de API é necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa mais altos:
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{
      "code": "await page.click(\"#next-page\"); await page.waitForLoadState(\"networkidle\"); const title = await page.title(); JSON.stringify({ title });",
      "language": "node",
      "timeout": 30
    }'
  ```

  ```bash CLI theme={null}
  # Usa o último scraping automaticamente
  firecrawl interact -c "
    await page.click('#next-page');
    await page.waitForLoadState('networkidle');
    const title = await page.title();
    const content = await page.\$eval('.article-body', el => el.textContent);
    JSON.stringify({ title, content });
  "

  # Ou passe um ID de scraping explicitamente
  # firecrawl interact <scrape-id> -c "await page.title()"
  ```
</CodeGroup>

<div id="python">
  ### Python
</div>

Defina `language` como `"python"` para a API do Python do Playwright.

<CodeGroup>
  ```python Python theme={null}
  response = app.interact(
      scrape_id,
      code="""
  import json

  await page.click('#load-more')
  await page.wait_for_load_state('networkidle')

  items = await page.query_selector_all('.item')
  data = []
  for item in items:
      text = await item.text_content()
      data.append(text.strip())

  print(json.dumps(data))
  """,
      language="python",
  )
  print(response.stdout)
  ```

  ```js Node theme={null}
  const response = await app.interact(scrapeId, {
    code: `
  import json

  await page.click('#load-more')
  await page.wait_for_load_state('networkidle')

  items = await page.query_selector_all('.item')
  data = []
  for item in items:
      text = await item.text_content()
      data.append(text.strip())

  print(json.dumps(data))
  `,
    language: 'python',
  });
  console.log(response.stdout);
  ```

  ```bash cURL theme={null}
  # Nenhuma chave de API é necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa maiores:
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{
      "code": "import json\nawait page.click(\"#load-more\")\nawait page.wait_for_load_state(\"networkidle\")\nitems = await page.query_selector_all(\".item\")\ndata = [await i.text_content() for i in items]\nprint(json.dumps(data))",
      "language": "python"
    }'
  ```

  ```bash CLI theme={null}
  firecrawl interact --python -c "
  import json
  await page.click('#load-more')
  await page.wait_for_load_state('networkidle')
  items = await page.query_selector_all('.item')
  data = [await i.text_content() for i in items]
  print(json.dumps(data))
  "
  ```
</CodeGroup>

<div id="bash-agent-browser">
  ### Bash (agent-browser)
</div>

[agent-browser](https://github.com/vercel-labs/agent-browser) é uma CLI pré-instalada no sandbox com mais de 60 comandos. Ela fornece uma árvore de acessibilidade com refs de elementos (`@e1`, `@e2`, ...), o que é ideal para automação conduzida por LLM.

<CodeGroup>
  ```python Python theme={null}
  # Tire um snapshot para ver elementos interativos
  snapshot = app.interact(
      scrape_id,
      code="agent-browser snapshot -i",
      language="bash",
  )
  print(snapshot.stdout)
  # Resultado:
  # [document]
  #   @e1 [input type="text"] "Search..."
  #   @e2 [button] "Search"
  #   @e3 [link] "About"

  # Interaja com elementos usando @refs
  app.interact(
      scrape_id,
      code='agent-browser fill @e1 "firecrawl" && agent-browser click @e2',
      language="bash",
  )
  ```

  ```js Node theme={null}
  // Tire um snapshot para ver elementos interativos
  const snapshot = await app.interact(scrapeId, {
    code: 'agent-browser snapshot -i',
    language: 'bash',
  });
  console.log(snapshot.stdout);
  // Resultado:
  // [document]
  //   @e1 [input type="text"] "Search..."
  //   @e2 [button] "Search"
  //   @e3 [link] "About"

  // Interaja com elementos usando @refs
  await app.interact(scrapeId, {
    code: 'agent-browser fill @e1 "firecrawl" && agent-browser click @e2',
    language: 'bash',
  });
  ```

  ```bash cURL theme={null}
  # Tire um snapshot para ver elementos interativos
  # Nenhuma API key necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa maiores:
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"code": "agent-browser snapshot -i", "language": "bash"}'

  # Interaja com elementos usando @refs
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"code": "agent-browser fill @e1 \"firecrawl\" && agent-browser click @e2", "language": "bash"}'
  ```

  ```bash CLI theme={null}
  # Tire um snapshot para ver elementos interativos
  firecrawl interact --bash -c "agent-browser snapshot -i"

  # Interaja com elementos usando @refs
  firecrawl interact --bash -c 'agent-browser fill @e1 "firecrawl" && agent-browser click @e2'
  ```
</CodeGroup>

Comandos comuns do agent-browser:

| Comando                   | Descrição                                               |
| ------------------------- | ------------------------------------------------------- |
| `snapshot`                | Árvore de acessibilidade completa com refs de elementos |
| `snapshot -i`             | Apenas elementos interativos                            |
| `click @e1`               | Clica no elemento pela ref                              |
| `fill @e1 "text"`         | Limpa o campo e digita o texto                          |
| `type @e1 "text"`         | Digita sem limpar                                       |
| `press Enter`             | Pressiona uma tecla do teclado                          |
| `scroll down 500`         | Rola 500 pixels para baixo                              |
| `get text @e1`            | Obtém o conteúdo de texto                               |
| `get url`                 | Obtém a URL atual                                       |
| `wait @e1`                | Aguarda o elemento                                      |
| `wait --load networkidle` | Aguarda a rede ficar inativa                            |
| `find text "X" click`     | Encontra o elemento pelo texto e clica                  |
| `screenshot`              | Tira uma captura de tela da página atual                |
| `eval "js code"`          | Executa JavaScript na página                            |

<div id="live-view">
  ## Visualização em tempo real
</div>

Toda resposta de `interact` retorna uma `liveViewUrl` que você pode incorporar para acompanhar o navegador em tempo real. Útil para depuração, demonstrações ou para criar UIs com navegador.

```json Response theme={null}
{
  "success": true,
  "cdpUrl": "wss://browser.firecrawl.dev/...",
  "liveViewUrl": "https://liveview.firecrawl.dev/...",
  "interactiveLiveViewUrl": "https://liveview.firecrawl.dev/...",
  "stdout": "",
  "result": "...",
  "exitCode": 0
}
```

```html theme={null}
<iframe src="LIVE_VIEW_URL" width="100%" height="600" />
```

<div id="interactive-live-view">
  ### Visualização em tempo real interativa
</div>

A resposta também inclui uma `interactiveLiveViewUrl`. Diferentemente da visualização em tempo real padrão, que é somente para visualização, a visualização em tempo real interativa permite que os usuários cliquem, digitem e interajam com a sessão do navegador diretamente pelo stream incorporado. Isso é útil para criar interfaces de navegador voltadas para o usuário final, como fluxos de login ou fluxos de trabalho guiados em que os usuários finais precisam controlar o navegador.

```html theme={null}
<iframe src="INTERACTIVE_LIVE_VIEW_URL" width="100%" height="600" />
```

<div id="cdp-url">
  ### URL do CDP
</div>

Toda resposta de interação também retorna uma `cdpUrl`: a URL WebSocket bruta do Chrome DevTools Protocol (CDP) da sessão do navegador. Use-a para se conectar diretamente à sessão ativa pelo Playwright, Puppeteer ou qualquer cliente CDP e controlar o navegador com seu próprio código.

```js theme={null}
import { chromium } from "playwright";

const browser = await chromium.connectOverCDP(cdpUrl);
const context = browser.contexts()[0];
const page = context.pages()[0];
```

<div id="session-lifecycle">
  ## Ciclo de vida da sessão
</div>

<div id="creation">
  ### Criação
</div>

A primeira `POST /v2/scrape/{scrapeId}/interact` dá continuidade à sessão de scraping e inicia a interação.

<div id="reuse">
  ### Reutilização
</div>

Chamadas subsequentes de `interact` no mesmo `scrapeId` reutilizam a sessão existente. O navegador permanece aberto e mantém seu estado entre as chamadas, para que você possa encadear várias interações:

<CodeGroup>
  ```python Python theme={null}
  # Primeira chamada: clicar em uma aba
  app.interact(scrape_id, code="await page.click('#tab-2')")

  # Segunda chamada: a aba ainda está selecionada, extrair seu conteúdo
  result = app.interact(scrape_id, code="await page.$eval('#tab-2-content', el => el.textContent)")
  print(result.result)
  ```

  ```js Node theme={null}
  // Primeira chamada: clicar em uma aba
  await app.interact(scrapeId, { code: "await page.click('#tab-2')" });

  // Segunda chamada: a aba ainda está selecionada, extrair seu conteúdo
  const result = await app.interact(scrapeId, {
    code: "await page.$eval('#tab-2-content', el => el.textContent)",
  });
  console.log(result.result);
  ```

  ```bash CLI theme={null}
  # Primeira chamada: clicar em uma aba
  firecrawl interact -c "await page.click('#tab-2')"

  # Segunda chamada: a aba ainda está selecionada, extrair seu conteúdo
  firecrawl interact -c "await page.\$eval('#tab-2-content', el => el.textContent)"
  ```
</CodeGroup>

<div id="cleanup">
  ### Limpeza
</div>

Encerre a sessão explicitamente quando terminar:

<CodeGroup>
  ```python Python theme={null}
  app.stop_interaction(scrape_id)
  ```

  ```js Node theme={null}
  await app.stopInteraction(scrapeId);
  ```

  ```bash cURL theme={null}
  # Nenhuma API key necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa maiores:
  curl -s -X DELETE "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact"
  ```

  ```bash CLI theme={null}
  # Para a última sessão de scraping
  firecrawl interact stop

  # Ou pare uma sessão específica pelo ID
  # firecrawl interact stop <scrape-id>
  ```
</CodeGroup>

As sessões também expiram automaticamente com base no TTL (default: 10 minutes) ou no tempo limite de inatividade (default: 5 minutes).

<Warning>
  Sempre encerre as sessões quando terminar para evitar cobrança desnecessária. Os créditos são rateados por segundo.
</Warning>

<div id="persistent-profiles-with-scrape-interact">
  ## Perfis persistentes com Scrape + Interagir
</div>

Por padrão, cada sessão de scraping + interagir começa com um navegador limpo. Com `profile`, você pode salvar e reutilizar o estado do navegador (cookies, localStorage, sessões) entre scrapes. Isso é útil para continuar conectado e preservar preferências.

Passe o objeto `profile` na requisição inicial `POST /v2/scrape`. Não passe `profile` para `POST /v2/scrape/{scrapeId}/interact`; a sessão de interagir reutiliza a sessão do navegador e as configurações de perfil do scrape job. Encerre a sessão de interagir com `DELETE /v2/scrape/{scrapeId}/interact` para que mudanças graváveis no perfil possam ser salvas.

```bash cURL theme={null}
curl -X POST "https://api.firecrawl.dev/v2/scrape" \
  -H "Authorization: Bearer fc-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "formats": ["markdown"],
    "profile": {
      "name": "my-profile",
      "saveChanges": true
    }
  }'

curl -X POST "https://api.firecrawl.dev/v2/scrape/SCRAPE_ID/interact" \
  -H "Authorization: Bearer fc-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Click the login button"
  }'

curl -X DELETE "https://api.firecrawl.dev/v2/scrape/SCRAPE_ID/interact" \
  -H "Authorization: Bearer fc-YOUR_API_KEY"
```

O ciclo de vida do perfil é:

1. Crie o scraping com `profile.name` e `saveChanges: true`.
2. Execute interações por prompt ou código usando o `scrapeId` retornado.
3. Encerre a sessão para salvar cookies, localStorage e outros estados do navegador.
4. Inicie um scraping posterior com o mesmo `profile.name`. Use `saveChanges: false` quando quiser apenas ler o estado existente sem gravar as mudanças de volta.

<CodeGroup>
  ```python Python theme={null}
  from firecrawl import Firecrawl

  app = Firecrawl(
    # Nenhuma API key necessária para começar — adicione uma para limites de taxa mais altos:
    # api_key="fc-YOUR-API-KEY",
  )

  # Sessão 1: Scraping com um perfil, autentique-se e encerre (o estado é salvo)
  result = app.scrape(
      "https://app.example.com/login",
      formats=["markdown"],
      profile={"name": "my-app", "save_changes": True},
  )
  scrape_id = result.metadata.scrape_id

  app.interact(scrape_id, prompt="Fill in user@example.com and password, then click Login")
  app.stop_interaction(scrape_id)

  # Sessão 2: Scraping com o mesmo perfil em modo somente leitura - já autenticado
  result = app.scrape(
      "https://app.example.com/dashboard",
      formats=["markdown"],
      profile={"name": "my-app", "save_changes": False},
  )
  scrape_id = result.metadata.scrape_id

  response = app.interact(scrape_id, prompt="Extract the dashboard data")
  print(response.output)
  app.stop_interaction(scrape_id)
  ```

  ```js Node theme={null}
  import { Firecrawl } from 'firecrawl';

  const app = new Firecrawl({
    // Nenhuma API key necessária para começar — adicione uma para limites de taxa mais altos:
    // apiKey: 'fc-YOUR-API-KEY',
  });

  // Session 1: Scrape com um perfil, faça login e pare (o estado é salvo)
  const result1 = await app.scrape('https://app.example.com/login', {
    formats: ['markdown'],
    profile: { name: 'my-app', saveChanges: true },
  });
  const scrapeId1 = result1.metadata?.scrapeId;

  await app.interact(scrapeId1, { prompt: 'Fill in user@example.com and password, then click Login' });
  await app.stopInteraction(scrapeId1);

  // Sessão 2: Scraping com o mesmo perfil em modo somente leitura - já autenticado
  const result2 = await app.scrape('https://app.example.com/dashboard', {
    formats: ['markdown'],
    profile: { name: 'my-app', saveChanges: false },
  });
  const scrapeId2 = result2.metadata?.scrapeId;

  const response = await app.interact(scrapeId2, { prompt: 'Extract the dashboard data' });
  console.log(response.output);
  await app.stopInteraction(scrapeId2);
  ```

  ```bash cURL theme={null}
  # Session 1: Scrape with a profile
  # Nenhuma API key necessária para começar — adicione -H "Authorization: Bearer $FIRECRAWL_API_KEY" para limites de taxa mais altos:
  RESPONSE=$(curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://app.example.com/login",
      "formats": ["markdown"],
      "profile": { "name": "my-app", "saveChanges": true }
    }')

  SCRAPE_ID=$(echo $RESPONSE | jq -r '.data.metadata.scrapeId')

  # Log in via interact
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Fill in user@example.com and password, then click Login"}'

  # Parar — o estado é salvo no perfil
  curl -s -X DELETE "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact"

  # Sessão 2: Scraping novamente com o mesmo perfil em modo somente leitura — já autenticado
  RESPONSE=$(curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://app.example.com/dashboard",
      "formats": ["markdown"],
      "profile": { "name": "my-app", "saveChanges": false }
    }')

  SCRAPE_ID=$(echo $RESPONSE | jq -r '.data.metadata.scrapeId')

  curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Extract the dashboard data"}'
  ```

  ```bash CLI theme={null}
  # Sessão 1: Scraping com um perfil, faça login e pare (estado é salvo)
  firecrawl scrape https://app.example.com/login --profile my-app
  firecrawl interact "Fill in user@example.com and password, then click Login"
  firecrawl interact stop

  # Sessão 2: Scraping com o mesmo perfil — já autenticado
  firecrawl scrape https://app.example.com/dashboard --profile my-app
  firecrawl interact "Extract the dashboard data"
  firecrawl interact stop

  # Somente leitura: carrega o estado do perfil sem salvar mudanças
  firecrawl scrape https://app.example.com/dashboard --profile my-app --no-save-changes
  ```
</CodeGroup>

| Parâmetro     | Padrão | Descrição                                                                                                                                                                                                                                  |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`        | None   | Um nome para o perfil persistente. Scrapes com o mesmo nome compartilham o estado do navegador.                                                                                                                                            |
| `saveChanges` | `true` | Quando `true`, o estado do navegador é salvo novamente no perfil quando a sessão de interagir é encerrada. Defina como `false` para carregar dados existentes sem gravar, o que é útil quando você precisa de vários leitores simultâneos. |

<Note>
  Apenas uma sessão pode salvar em um perfil por vez. Se outra sessão já estiver salvando, você receberá um erro `409`. Você ainda pode abrir o mesmo perfil com `saveChanges: false` ou tentar novamente mais tarde.
</Note>

O estado do navegador é salvo quando a sessão de interagir é encerrada. Sempre encerre a sessão quando terminar para que o perfil possa ser reutilizado.

<div id="validate-persistence">
  ### Validar a persistência
</div>

Você pode testar a persistência sem depender de um fluxo de login real gravando um valor no `localStorage` em uma sessão, encerrando-a e, em seguida, lendo esse valor em uma segunda sessão com o mesmo perfil.

```bash cURL theme={null}
# Sessão 1: gravar o estado do navegador e salvá-lo
RESPONSE=$(curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "formats": ["markdown"],
    "profile": { "name": "profile-validation", "saveChanges": true }
  }')

SCRAPE_ID=$(echo "$RESPONSE" | jq -r ".data.metadata.scrapeId")

curl -s -X POST "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "await page.evaluate(() => { localStorage.setItem(\"firecrawlProfileCheck\", \"saved\"); document.cookie = \"firecrawl_profile_check=saved; path=/; max-age=3600\"; return localStorage.getItem(\"firecrawlProfileCheck\"); });"
  }'

curl -s -X DELETE "https://api.firecrawl.dev/v2/scrape/$SCRAPE_ID/interact" \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY"
```

A segunda resposta do Interagir deve mostrar `localStorage` como `"saved"` e `cookie` como `true`.

<Info>
  Os perfis criados via API talvez ainda não apareçam em painel > Interagir > Perfis. No momento, o painel ainda não oferece uma visão completa dos perfis persistentes criados via API.
</Info>

<div id="when-to-use-what">
  ## Quando usar o quê
</div>

| Use Case                                | Recommended                      | Why                                           |
| --------------------------------------- | -------------------------------- | --------------------------------------------- |
| Busca na web                            | [Search](/pt-BR/features/search) | Endpoint de busca dedicado                    |
| Obter conteúdo limpo de uma URL         | [Scrape](/pt-BR/features/scrape) | Uma chamada de API, sem necessidade de sessão |
| Clicar, digitar e navegar em uma página | **Interagir** (prompt)           | Basta descrever em inglês                     |
| Extrair dados por trás das interações   | **Interagir** (prompt)           | Não são necessários seletores                 |
| Lógica de scraping complexa             | **Interagir** (code)             | Controle total do Playwright                  |

<Info>
  **Interagir vs Browser Sandbox**: O Interagir é construído sobre a mesma infraestrutura que o [Browser Sandbox](/pt-BR/features/browser), mas oferece uma interface melhor para o padrão mais comum: fazer scrape de uma página e depois se aprofundar. O Browser Sandbox é melhor quando você precisa de uma sessão do navegador independente que não esteja vinculada a um scrape específico.
</Info>

<div id="pricing">
  ## Preços
</div>

* **Somente código** (sem `prompt`): 2 créditos por minuto de sessão
* **Com prompts de IA**: 7 créditos por minuto de sessão
* **Scraping**: cobrado separadamente (1 crédito por scraping, além de quaisquer custos específicos do formato)

<div id="api-reference">
  ## Referência da API
</div>

* [Execute Interagir](/pt-BR/api-reference/endpoint/scrape-execute): `POST /v2/scrape/{scrapeId}/interact`
* [Stop Interagir](/pt-BR/api-reference/endpoint/scrape-browser-delete): `DELETE /v2/scrape/{scrapeId}/interact`

<div id="request-body-post">
  ### Corpo da Requisição (POST)
</div>

| Campo      | Tipo     | Padrão   | Descrição                                                                                                                |
| ---------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `prompt`   | `string` | Nenhum   | Tarefa em linguagem natural para o agente de IA. Obrigatório se `code` não estiver definido. Máx. 10.000 caracteres.     |
| `code`     | `string` | Nenhum   | Código a ser executado (Node.js, Python ou Bash). Obrigatório se `prompt` não estiver definido. Máx. 100.000 caracteres. |
| `language` | `string` | `"node"` | `"node"`, `"python"` ou `"bash"`. Usado apenas com `code`.                                                               |
| `timeout`  | `number` | `30`     | Tempo limite em segundos (1–300).                                                                                        |
| `origin`   | `string` | Nenhum   | Identificador do chamador para acompanhamento de atividades.                                                             |

<div id="response">
  ### Resposta
</div>

| Field                    | Description                                                                                                                                                     |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `success`                | `true` se a execução for concluída sem erros                                                                                                                    |
| `cdpUrl`                 | URL WebSocket bruta do Chrome DevTools Protocol (CDP) para a sessão do navegador. Conecte-se diretamente com Playwright, Puppeteer ou qualquer cliente CDP      |
| `liveViewUrl`            | URL de visualização em tempo real somente leitura para a sessão do navegador                                                                                    |
| `interactiveLiveViewUrl` | URL de visualização em tempo real interativa (os visualizadores podem controlar o navegador)                                                                    |
| `output`                 | A resposta em linguagem natural do agente ao seu prompt. Presente apenas ao usar `prompt`.                                                                      |
| `stdout`                 | Saída padrão da execução do código                                                                                                                              |
| `result`                 | Valor bruto retornado do sandbox. Para `code`: a última expressão avaliada. Para `prompt`: o snapshot bruto da página que o agente usou para produzir `output`. |
| `stderr`                 | Saída de erro padrão                                                                                                                                            |
| `exitCode`               | Código de saída (`0` = sucesso)                                                                                                                                 |
| `killed`                 | `true` se a execução tiver sido encerrada devido a tempo limite                                                                                                 |

***

Tem feedback ou precisa de ajuda? Envie um e-mail para [help@firecrawl.com](mailto:help@firecrawl.com) ou entre em contato no [Discord](https://discord.gg/firecrawl).
