# Lifecycle


Every trace needs at least one container span. A container is the unit of work Flare organises everything else around. In a browser that unit is a page view.

## Browser container types

| Type | What it is |
|---|---|
| `browser_pageload` | The browser loading a document |
| `browser_navigation` | Your router swapping the view without loading a document |
| `browser_web_vital` | A page's late arriving vitals |

A browser trace is rooted in `browser_pageload` or `browser_navigation`. Everything else, so `browser_fetch`, `browser_xhr` and `browser_component`, reaches one of those two by following `parentSpanId` and never appears as a root span itself. A trace whose root is not a container type fails processing.

The PHP containers, and the optional `php_application` wrapper around them, are covered in the [PHP lifecycle page](/docs/protocol/traces/lifecycle).

## What a browser trace looks like

You send spans as a flat list, in the order they finished. `parentSpanId` is what carries the shape:

| `spanId` | `parentSpanId` | Type | Name |
|---|---|---|---|
| `2b3c…8192` | `1a2b…7081` | `browser_fetch` | `GET /api/products/9f2c` |
| `4d5e…a3b4` | `3c4d…92a3` | `browser_component` | `PriceTag` |
| `6f70…c5d6` | `3c4d…92a3` | `browser_component` | `AddToCart` |
| `3c4d…92a3` | `1a2b…7081` | `browser_component` | `ProductPage` |
| `1a2b…7081` | `null` | `browser_pageload` | `/products/{id}` |

Which Flare displays as:

```
browser_pageload  /products/{id}
├── browser_fetch  GET /api/products/9f2c
└── browser_component  ProductPage
    ├── browser_component  PriceTag
    └── browser_component  AddToCart
```

`PriceTag` and `AddToCart` point at `ProductPage`, not at the page load. The flat list has nothing else to record that relationship with, so pointing every component at the container throws it away. Keeping it means a slow parent with fast children tells you the time went into the parent's own work.

The children also appear before their parent, and the root appears last. Components finish from the inside out, so that is the natural order to send them in. You do not have to sort the array. Flare reads the whole payload before resolving parents, so any order works.

Span events are the exception to all of this. They live in the `events` array of the span they belong to, so they really are nested inside it.

Each client-side route change starts a new trace with its own `browser_navigation` root. A single page app that runs for an hour produces many traces, not one enormous one.

## Parent references across requests

Normally a span's `parentSpanId` has to point at a span in the same request. Flare finds a span's container by walking up the parent chain, so if the parent never arrived, the span drops out of the trace, and sometimes others with it. The request still returns a success response, so nothing tells you the data went missing.

Container spans are the exception. A container may name a parent that arrived in an earlier request.

This is the whole reason `browser_web_vital` is a container. It goes out minutes after its `browser_pageload` parent, in a request of its own, and still attaches to the right page. See [Web vitals](/docs/protocol-javascript/traces/web-vitals).
