> For the complete documentation index, see [llms.txt](https://docs.eyepop.ai/developer-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.eyepop.ai/developer-documentation/getting-started.md).

# Getting Started

### Step 1 — Create an Account & Get Your API Key

1. Sign up at [eyepop.ai](https://eyepop.ai).
2. Open the [dashboard](https://dashboard.eyepop.ai) and navigate to **API Keys**.
3. Generate a new API key — it will look like `eyp_...`.
4. Store it as an environment variable:

```bash
export EYEPOP_API_KEY=eyp_...
```

> Never hardcode your API key. Load it from the environment or a `.env` file.

***

### Step 2 — Install the SDK

**Python (3.12+)**

```bash
pip install eyepop
```

**Node / React**

```bash
npm install --save @eyepop.ai/eyepop
```

**Browser (CDN)**

```html
<script src="https://cdn.jsdelivr.net/npm/@eyepop.ai/eyepop/dist/eyepop.min.js"></script>
```

***

### Step 3 — Connect to Your Pop

#### Python

The primary entry point is `async_worker()`. Use it with `async with` so the connection is automatically closed.

```python
import asyncio
from eyepop import EyePopSdk

async def main():
    async with EyePopSdk.async_worker() as endpoint:
        # endpoint is ready — EYEPOP_API_KEY is read from the environment
        pass

asyncio.run(main())
```

The SDK reads `EYEPOP_API_KEY` and `EYEPOP_URL` from the environment automatically. You can also pass the key explicitly:

```python
async with EyePopSdk.async_worker(api_key="eyp_...") as endpoint:
    ...
```

For scripts where async is not available (rare, one-shot image only):

```python
from eyepop import EyePopSdk

with EyePopSdk.workerEndpoint() as endpoint:
    result = endpoint.upload("image.jpg").predict()
```

#### Node / TypeScript

```typescript
import { EyePop } from '@eyepop.ai/eyepop'

const endpoint = await EyePop.workerEndpoint({ auth: { secretKey: process.env.EYEPOP_SECRET_KEY } }).connect()
try {
  // endpoint is ready
} finally {
  await endpoint.disconnect()
}
```

***

### Step 4 — Configure a Pop

A Pop defines what models run on your endpoint. Set it after connecting:

#### Python

```python
from eyepop.worker.worker_types import Pop, InferenceComponent

pop = Pop(components=[
    InferenceComponent(ability='eyepop.person:latest')
])

async with EyePopSdk.async_worker() as endpoint:
    await endpoint.set_pop(pop)
    # now run predictions
```

#### Node / TypeScript

```typescript
await endpoint.changePop({
    components: [{ ability: 'eyepop.person:latest' }]
})
```

***

### Step 5 — Run Your First Prediction

#### Upload a local file

**Python**

```python
async with EyePopSdk.async_worker() as endpoint:
    await endpoint.set_pop(pop)
    job = await endpoint.upload("image.jpg")
    result = await job.predict()
    print(result)
```

**Node**

```typescript
const results = await endpoint.process({ file: 'image.jpg' })
for await (const result of results) {
    console.log(result)
}
```

#### Load from a URL or RTSP stream

**Python**

```python
job = await endpoint.load_from("https://example.com/photo.jpg")
result = await job.predict()

# or an RTSP camera stream
job = await endpoint.load_from("rtsp://camera-ip/stream")
while result := await job.predict():
    print(result)
```

**Node**

```typescript
const results = await endpoint.process({ url: 'https://example.com/video.mp4' })
for await (const result of results) {
    console.log(result)
}
```

***

### Step 6 — Understand the Output

Predictions return structured JSON. Example response:

```json
{
  "source_width": 1920,
  "source_height": 1080,
  "seconds": 0.083,
  "objects": [
    {
      "classLabel": "person",
      "confidence": 0.95,
      "x": 100,
      "y": 50,
      "width": 80,
      "height": 200
    }
  ]
}
```

| Result key | Used by                                                                     |
| ---------- | --------------------------------------------------------------------------- |
| `objects`  | Detection abilities (`eyepop.person:latest`, `eyepop.vehicle:latest`, etc.) |
| `classes`  | Classification abilities                                                    |
| `texts`    | VLM / describe abilities and OCR                                            |

***

### Step 7 — Process Video (Async Frame Loop)

For video files or live streams, iterate frame-by-frame:

```python
async with EyePopSdk.async_worker() as endpoint:
    await endpoint.set_pop(pop)
    job = await endpoint.upload("video.mp4")
    while result := await job.predict():
        print(result)   # one result per frame
```

To process at a lower frame rate (e.g., 1 fps):

```python
job = await endpoint.upload("video.mp4", target_fps=1)
```

***

### Step 8 — Batch Processing

Process multiple files concurrently using `asyncio.gather`:

```python
import asyncio
from eyepop import EyePopSdk
from eyepop.worker.worker_types import Pop, InferenceComponent

FILES = ["img1.jpg", "img2.jpg", "img3.jpg"]

async def process(endpoint, path):
    job = await endpoint.upload(path)
    return await job.predict()

async def main():
    pop = Pop(components=[InferenceComponent(ability='eyepop.person:latest')])
    async with EyePopSdk.async_worker() as endpoint:
        await endpoint.set_pop(pop)
        results = await asyncio.gather(*[process(endpoint, f) for f in FILES])
    for r in results:
        print(r)

asyncio.run(main())
```

***

### Step 9 — Visualization

```python
from eyepop import EyePopSdk
from PIL import Image
import matplotlib.pyplot as plt

with Image.open("image.jpg") as image:
    plt.imshow(image)

plot = EyePopSdk.plot(plt.gca())
plot.prediction(result)
plt.show()
```

**Node / Canvas (browser or Node)**

```typescript
import Render2d from '@eyepop.ai/eyepop-render-2d'

const renderer = Render2d.renderer(context, [
    Render2d.renderBox({ showClass: true, showConfidence: true })
])
renderer.draw(result)
```

***

### Step 10 — Live Browser Streams (Node / Browser only)

Connect a browser `MediaStream` directly to an EyePop endpoint:

```typescript
const stream = await navigator.mediaDevices.getUserMedia({ video: true })
const ingressId = await endpoint.liveIngress(stream)
const results = await endpoint.process({ ingressId })
for await (const result of results) {
    console.log(result)
}
```

> `liveIngress` is a browser/Node API and takes a `MediaStream`. It is not available in the Python SDK.

***

### Step 11 — Authentication Options

| Method                                | Use case                                                                          |
| ------------------------------------- | --------------------------------------------------------------------------------- |
| `api_key=` / `EYEPOP_API_KEY` env var | Server-side — standard `eyp_...` key for transient cloud inference                |
| `secret_key=`                         | Server-side — long encoded key for named pops                                     |
| Session token                         | Browser apps — generate a short-lived token server-side and pass it to the client |
| OAuth2                                | Development / dashboard login only                                                |

**Python — standard (transient pop)**

```python
# Preferred: let the SDK read EYEPOP_API_KEY from the environment
async with EyePopSdk.async_worker() as endpoint: ...

# Or pass explicitly
async with EyePopSdk.async_worker(api_key="eyp_...") as endpoint: ...
```

**Python — named pop with secret key**

```python
async with EyePopSdk.async_worker(secret_key="<long-encoded-key>") as endpoint: ...
```

> `api_key` and `secret_key` are not interchangeable. Passing an `eyp_...` key as `secret_key` raises a `ValueError` at runtime.

**Node — generate a session token for browser clients**

```typescript
// Server side
const sessionToken = await endpoint.session()

// Browser client
const clientEndpoint = await EyePop.workerEndpoint({ auth: { session: sessionToken } }).connect()
```

***

### Step 12 — Deploy On-Premise (Optional)

EyePop supports on-premise deployment for IP camera workflows. Run `eyepop-instance` locally to process RTSP streams with cloud inference offload and a local dashboard.

Use `is_local_mode=True` in the SDK to connect to a local instance instead of the cloud:

```python
async with EyePopSdk.async_worker(is_local_mode=True) as endpoint:
    await endpoint.set_pop(pop)
    job = await endpoint.upload("image.jpg")
    result = await job.predict()
```

***

### Tuning Options

| Option                | Python             | Node               | Effect                              |
| --------------------- | ------------------ | ------------------ | ----------------------------------- |
| Disable auto-start    | `auto_start=False` | `autoStart: false` | Don't start a worker on connect     |
| Preserve pending jobs | `stop_jobs=False`  | `stopJobs: false`  | Keep queued jobs when disconnecting |

***

### Resources

* [Dashboard](https://dashboard.eyepop.ai)
* [Python SDK](https://github.com/eyepop-ai/eyepop-sdk-python)
* [Node SDK](https://github.com/eyepop-ai/eyepop-sdk-node)
* [Example projects](https://github.com/eyepop-ai/Labs)
* [Full documentation](https://docs.eyepop.ai)
