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

# Network & edge

> Manage custom domains, DNS, edge analytics, error tracking, request logs, latency percentiles and cache invalidation for website applications.

The `network` module is only available on **website applications**. Narrow the type with `app.isWebsite()` first:

```typescript theme={null}
const app = await api.applications.fetch("abc123def456abc123def456");

if (!app.isWebsite()) {
    throw new Error("This application is not a website");
}

app.network; // NetworkModule
```

## Custom domain

`app.network.setCustomDomain(domain)` sets or removes the custom domain bound to the website.

```typescript theme={null}
await app.network.setCustomDomain("yoursite.com");

// Pass "@" to remove the configured custom domain
await app.network.setCustomDomain("@");
```

<Note>
  Custom domains require a [Senior plan](https://squarecloud.app/plans) or higher. There is a daily
  per-user limit on how many times you can change a custom domain.
</Note>

<Warning>
  Attaching a custom domain beyond your plan's load balancer limit (see
  [Account-wide domains and load balancers](#account-wide-domains-and-load-balancers) below) fails
  with `LOAD_BALANCER_LIMIT_REACHED` (403).
</Warning>

## DNS records

After attaching a custom domain you need to configure DNS at your registrar. `app.network.dns()` returns an array of DNS records to create.

```typescript theme={null}
const records = await app.network.dns();

for (const record of records) {
    console.log(`${record.type.toUpperCase()} ${record.name} → ${record.value} (${record.status})`);
}
```

Each record is `{ type, name, value, status }`:

* `type` is `"txt"` or `"cname"`. TXT records cover domain ownership and SSL validation; the CNAME record carries traffic and always points `value` at `cname.squareweb.app`.
* `status` reflects the current validation state, e.g. `"pending"`, `"pending_validation"`, or `"active"`.

## Analytics

`app.network.analytics({ start, end })` returns aggregated edge analytics. `start` and `end` accept either ISO 8601 strings or `Date` objects. Maximum retention window is **7 days**.

```typescript theme={null}
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);

const analytics = await app.network.analytics({
    start: since,
    end: new Date(),
});

if ("visits" in analytics) {
    console.log(analytics.visits.length, "time buckets");
    console.log("Top countries:", analytics.countries.slice(0, 5));
    console.log("Top paths:",     analytics.paths.slice(0, 5));
}
```

<Warning>
  For empty windows (e.g. before the app was created) the API returns `{}`. Guard with `"visits" in analytics` before reading.
</Warning>

### Drill-down filters

Beyond `start`/`end`, `analytics()` accepts optional filters. Each filter narrows every breakdown in the response at once, not just one of them:

| Filter        | Notes                                                                        |
| ------------- | ---------------------------------------------------------------------------- |
| `country`     | 2-letter country code, e.g. `"BR"`                                           |
| `ip`          | Exact IP match                                                               |
| `path`        | Prefix match, e.g. `"/api"`                                                  |
| `status`      | HTTP status code, e.g. `"404"`                                               |
| `os`          | Operating system                                                             |
| `browser`     | Browser name                                                                 |
| `protocol`    | Request protocol                                                             |
| `referer`     | Use `"Direct"` for requests with no referer                                  |
| `provider`    | Network provider, e.g. `"GOOGLE (15169)"` (ASN) or `"SQUARE-CLOUD-PLATFORM"` |
| `contentType` | Use `"Unknown"` for unclassified content types                               |
| `bot`         | Use `"Unverified"` for normal (non-bot) traffic                              |

```typescript theme={null}
const analytics = await app.network.analytics({
    start: since,
    end: new Date(),
    country: "BR",
    status: "404",
    bot: "Unverified",
});
```

### Breakdowns

Alongside the existing time-series and top-N breakdowns, the response includes four breakdowns computed over the whole window (no time series): `ips` (IPs originating from Square Cloud's own network are masked), `status_codes`, `bots`, and `content_types`. Each entry has the shape `{ type, visits, requests, bytes }`.

```typescript theme={null}
if ("ips" in analytics) {
    console.log("Top IPs:",           analytics.ips.slice(0, 5));
    console.log("Status codes:",      analytics.status_codes);
    console.log("Bot traffic:",       analytics.bots);
    console.log("Content types:",     analytics.content_types);
}
```

## Error tracking

`app.network.errors({ start, end, include4xx? })` returns the edge error breakdown. By default only 5xx errors are included.

```typescript theme={null}
const errors = await app.network.errors({
    start: since,
    end: new Date(),
    include4xx: true, // include 4xx alongside 5xx
});

if ("summary" in errors) {
    console.log(`Total: ${errors.summary.total}`);
    console.log("By class:",          errors.summary.by_class);
    console.log("Top failing paths:", errors.top_paths.slice(0, 3));
}
```

## Per-request logs

`app.network.logs({ start, end })` returns the per-request edge logs.

```typescript theme={null}
const logs = await app.network.logs({ start: since, end: new Date() });

for (const log of logs.slice(0, 5)) {
    console.log(
        log.timestamp,
        log.request.method, log.request.path,
        "→",
        log.response.status,
        `(${log.client.country ?? "??"})`,
    );
}
```

<Note>
  Per-request logs require a [Pro plan](https://squarecloud.app/plans) or higher.
</Note>

## Latency percentiles

`app.network.performance({ start, end })` returns p50 / p95 / p99 latencies for the edge and origin layers.

```typescript theme={null}
const perf = await app.network.performance({ start: since, end: new Date() });

if ("summary" in perf) {
    const { p50, p95, p99 } = perf.summary.edge;
    console.log(`Edge p50/p95/p99: ${p50}/${p95}/${p99}ms`);
    console.log("Slowest paths:", perf.slowest_paths.slice(0, 3));
}
```

<Note>
  Performance metrics require a [Pro plan](https://squarecloud.app/plans) or higher.
</Note>

## Purging the edge cache

`app.network.purgeCache()` invalidates the entire edge cache for the application's domains.

```typescript theme={null}
await app.network.purgeCache();
```

## Account-wide domains and load balancers

`domains()` and `loadBalancers()` live on `api.applications`, not `app.network` — they operate across every application in the account rather than a single website.

### Listing every domain

`api.applications.domains()` returns every domain configured across all of the account's applications.

```typescript theme={null}
const domains = await api.applications.domains();

for (const domain of domains) {
    console.log(domain.app_id, domain.hostname, domain.type); // "subdomain" | "custom"
}
```

Custom domains are listed first; applications without a web domain are omitted. Results are served from cache and rate limited to 20 requests/60s per user, which does not count toward the per-application network rate limits described above.

### Load balancers

`api.applications.loadBalancers()` groups applications that share a custom domain.

```typescript theme={null}
const { limit, balancers } = await api.applications.loadBalancers();

for (const balancer of balancers) {
    console.log(balancer.hostname, balancer.apps.map((app) => app.name));
}
```

A group with 2 or more apps is an active load balancer: traffic is balanced at the edge with automatic failover when one of the apps is offline. `limit` is the maximum number of applications that can share one domain on the account's plan: 2 (Standard), 5 (Pro), 10 (Enterprise). Rate limited to 20 requests/60s per user.
