# How to Integrate ego-lite with Other Tools: 5 Integration Patterns for Browser Automation

> Discover 5 essential integration patterns for ego-lite. Seamlessly connect ego-lite with your existing tools for advanced browser automation and efficient CI/CD workflows.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-08-03

---

**You can integrate ego-lite with other tools by importing `installEgoSdk()` for programmatic use, piping scripts via CLI for CI pipelines, embedding in test runners with `__testing` overrides, orchestrating isolated task spaces with `newTaskSpace()`, or extending via site-specific learnings in `skills/ego-browser/learnings/`.**

ego-lite from [citrolabs/ego-lite](https://github.com/citrolabs/ego-lite) is a lightweight, Chrome DevTools Protocol (CDP)-based browser automation harness. Its architecture exposes a compact set of async helpers through the global `ego` object, making it straightforward to plug into CLI scripts, test runners, CI pipelines, and higher-level orchestrators. This guide covers how to integrate ego-lite with other tools using patterns derived directly from the source code.

---

## Core Architecture for Integration

Understanding ego-lite's internal structure helps you choose the right integration point.

| Component | Role | Source File |
|-----------|------|-------------|
| **Entry point** | Decides CLI (`runMain()`) vs module (`installEgoSdk()`) mode | [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) |
| **Helper Context** | Generates public API (`nav`, `click`, `type`, `waitFor`, etc.) | [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) |
| **Browser Runtime** | Manages CDP transport, session attach/re-attach, event buffering | [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) |
| **Element Resolver** | Resolves locators (`@ref`, `loc=css:…`, `xpath=…`) with failure classification | [`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts) |
| **Ref Management** | Maps numeric refs (`@21`) to backend node IDs, triggers re-snapshot | [`src/ref-map.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/ref-map.ts), [`src/ref-state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/ref-state.ts) |
| **Task Spaces** | Isolates browsing contexts, handles ownership (`agent` vs `user`) | [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts), [`src/env.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/env.ts) |
| **Learning Subsystem** | Loads site-specific tools from `skills/ego-browser/learnings/<site>/manifest.json` | [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) |
| **CLI Runner** | Reads JavaScript from stdin, wraps in async function, executes | [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts) |

All helpers are pure async functions returning promises, enabling seamless `await` from any JavaScript environment. Because helpers are generated at runtime, they stay synchronized with CDP session and task-space state automatically.

---

## Integration Pattern 1: Direct Node.js Script Import

**Programmatic integration** via `installEgoSdk()` gives you full control for embedding ego-lite in applications, services, or custom automation frameworks.

In [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts), the `installEgoSdk()` function injects helpers into a provided context (typically `globalThis`):

```javascript
// my-automation.js
import { installEgoSdk } from 'ego-browser';

installEgoSdk(globalThis);  // injects helpers into global scope

async function demo() {
  await nav('https://example.com');
  const btn = await locate('css:#login');
  await click(btn);
  await type('#password', 's3cr3t');
  await waitFor(() => locate('css:.dashboard'), 10);
}

demo().catch(console.error);

```

This pattern is ideal when you need to combine ego-lite with existing Node.js code, databases, or API clients.

---

## Integration Pattern 2: CLI Pipeline Integration

**Shell-piped execution** reads scripts from stdin via [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts), perfect for CI/CD pipelines and one-off commands.

```bash
echo "await nav('https://example.com'); await click('#login');" \
  | npx ego-browser

```

The `run()` function in [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts) handles the wrapping and execution:

```javascript
// From src/run.ts - conceptual flow
const userCode = await readStdin();
const wrapped = `(async () => { ${userCode} })()`;
await eval(wrapped);  // with helpers pre-injected

```

Use this pattern for GitHub Actions, GitLab CI, or shell-based workflows where installing Node.js dependencies is acceptable.

---

## Integration Pattern 3: Test Runner Embedding

**Test framework integration** leverages the `__testing` API (exposed in `src/helpers.test.mjs`) to stub the CDP layer for fast, deterministic unit tests.

```javascript
import { installEgoSdk, __testing } from 'ego-browser';

// Setup: stub CDP responses before initializing
__testing.setOverrides({
  sendCDPMessage: async (method, params) => {
    if (method === 'Runtime.evaluate') {
      return { result: { type: 'string', value: 'stubbed-title' } };
    }
    return {};
  }
});

installEgoSdk(globalThis);

test('page navigation returns correct title', async () => {
  await nav('https://example.com');
  const title = await evaluate(() => document.title);
  expect(title).toBe('stubbed-title');
});

```

For end-to-end tests with real browsers, reference `src/taskspace-e2e.test.mjs` which demonstrates full runtime exercise patterns.

---

## Integration Pattern 4: Multi-Task Space Orchestration

**Parallel browser isolation** uses `newTaskSpace()`, `switchTaskSpace()`, and `completeTaskSpace()` from [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) to run concurrent operations or segregate long-running jobs.

```javascript
import { installEgoSdk } from 'ego-browser';

installEgoSdk(globalThis);

async function worker(name, url) {
  const ts = await newTaskSpace(name);      // create isolated space
  await switchTaskSpace(ts.id);              // activate it
  await nav(url);
  const title = await evaluate(() => document.title);
  console.log(`[${name}] Title: ${title}`);
  await completeTaskSpace(ts.id, { keep: false });  // cleanup
}

// Run parallel crawls
await Promise.all([
  worker('github-scrape', 'https://github.com'),
  worker('npm-scrape', 'https://npmjs.com'),
  worker('docs-scrape', 'https://docs.github.com')
]);

```

Each task space maintains independent CDP session state, enabling scenarios like:

- Per-user browser sessions in multi-tenant applications
- Background jobs that don't block interactive automation
- A/B testing across isolated cookie/storage contexts

---

## Integration Pattern 5: Site-Specific Learning Extensions

**High-level tool integration** via the learning subsystem in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) lets other tools call semantic actions without knowing underlying selectors.

Add custom site logic under `skills/ego-browser/learnings/<site>/`:

```

skills/ego-browser/learnings/
├── github/
│   └── manifest.json
├── twitter/
│   └── manifest.json
└── custom-crm/
    └── manifest.json

```

Then invoke from any integration point:

```javascript
// After installing SDK
await nav('https://github.com');

// Semantic action - no CSS selectors needed
await runSiteTool('github', 'createIssue', {
  repo: 'myorg/myrepo',
  title: 'Automated bug report from CI',
  body: 'Generated by ego-lite integration'
});

// Extract structured data
const issues = await runSiteTool('github', 'listOpenIssues', {
  repo: 'myorg/myrepo',
  limit: 10
});

```

This pattern enables product teams to build reusable automation libraries that abstract away site-specific implementation details.

---

## Practical Integration Examples

### Complete Node.js Service Integration

```javascript
// services/scraper.js
import { installEgoSdk } from 'ego-browser';
import { saveToDatabase } from './db.js';

installEgoSdk(globalThis);

export async function scrapeProduct(url) {
  await nav(url);
  const price = await evaluate(() => 
    document.querySelector('.price').textContent
  );
  const inStock = await exists('css:.in-stock-badge');
  
  await saveToDatabase({ url, price, inStock, scrapedAt: new Date() });
  return { price, inStock };
}

```

### GitHub Actions CI Workflow

```yaml

# .github/workflows/data-quality.yml

name: Daily Data Quality Check
on:
  schedule:
    - cron: '0 6 * * *'  # 6 AM daily

jobs:
  verify-portal:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - run: npm ci
      
      - name: Run ego-lite validation
        run: |
          cat << 'EOF' | npx ego-browser
          await nav('https://internal-portal.example.com');
          await runSiteTool('portal', 'login', { 
            user: process.env.PORTAL_USER,
            pass: process.env.PORTAL_PASS 
          });
          const health = await runSiteTool('portal', 'checkHealth');
          if (!health.healthy) throw new Error(`Unhealthy: ${health.reason}`);
          console.log('Portal health verified');
          EOF
        env:
          PORTAL_USER: ${{ secrets.PORTAL_USER }}
          PORTAL_PASS: ${{ secrets.PORTAL_PASS }}

```

### Jest Test Suite with Stubbed CDP

```javascript
// __tests__/checkout-flow.test.js
import { installEgoSdk, __testing } from 'ego-browser';

beforeAll(() => {
  __testing.setOverrides({
    // Stub navigation to avoid real network calls
    sendCDPMessage: jest.fn(async (method, params) => {
      if (method === 'Page.navigate') {
        mockedCurrentUrl = params.url;
        return { frameId: 'mock-frame-1' };
      }
      if (method === 'Runtime.evaluate') {
        return { result: { value: `<html><body>Mock: ${mockedCurrentUrl}</body></html>` } };
      }
      return {};
    })
  });
  installEgoSdk(globalThis);
});

test('completes guest checkout', async () => {
  await nav('https://shop.example.com');
  await click('css:[data-testid="guest-checkout"]');
  await type('css:#email', 'test@example.com');
  await click('css:#place-order');
  
  const confirmation = await locate('css:.order-confirmation');
  expect(confirmation).toBeTruthy();
});

```

---

## Summary

- **Import `installEgoSdk()`** from [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) for direct programmatic control in Node.js applications.

- **Pipe scripts to stdin** via `npx ego-browser` for CLI and CI pipeline integration, handled by [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts).

- **Use `__testing.setOverrides()`** to stub CDP responses for fast, isolated unit tests in any test framework.

- **Orchestrate `newTaskSpace()` calls** for parallel, isolated browser contexts suitable for multi-tenant or concurrent scenarios.

- **Extend via site learnings** in `skills/ego-browser/learnings/<site>/` to expose semantic, reusable actions to other tools.

All patterns rely on ego-lite's core design: async helper functions generated at runtime that automatically synchronize with underlying CDP state in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts).

---

## Frequently Asked Questions

### Can I use ego-lite with Python or other non-JavaScript tools?

Not directly. ego-lite is a Node.js/TypeScript project built around CDP and JavaScript execution. For Python integration, use a subprocess approach: spawn `npx ego-browser` with Python's `subprocess`, pipe JavaScript code via stdin, and parse stdout. Alternatively, use a pure Python CDP library like [PyCDP](https://github.com/hyperiongray/pycdp) or [playwright-python](https://playwright.dev/python/) for native integration.

### How do I handle authentication sessions across multiple ego-lite integrations?

Use `switchTaskSpace()` to maintain persistent browser state. Create a task space once, perform login, then reuse that space ID across separate script invocations by storing the ID externally (database, Redis, file). Task spaces in [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) persist until `completeTaskSpace()` is called with `{ keep: false }`.

### What's the performance overhead of `installEgoSdk()` versus CLI execution?

Both use the same underlying runtime initialization in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts). The `installEgoSdk()` approach avoids subprocess overhead and allows connection reuse, making it faster for batch operations. CLI execution incurs ~200-500ms Node.js startup per invocation—acceptable for CI jobs, suboptimal for high-frequency automation loops.

### Does ego-lite support running without a real Chrome instance?

No. ego-lite requires a CDP-capable browser. The `__testing.setOverrides()` API in test files enables stubbing for unit tests, but production execution needs Chrome, Chromium, or a compatible browser launched with `--remote-debugging-port`. The runtime in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) manages this connection transparently.