---
title: "Build generative UI with Jev and json-render | Snowplow Signals"
description: "The fastest way to build generative UI that knows who is on the page. Signals hands Jev what this visitor is doing, in 6ms. json-render draws the answer."
source: https://signals.snowplow.io/lp/generative-ui
---

Generative UI with Jev

# Build generative UI with Jev + Signals + json-render.

Jev picks what goes in the spec in a fraction of a second. Signals gives it the state to pick from: what this visitor is doing right now, read in 6ms. json-render by Vercel draws the page from that spec and a catalog of your own components. One prompt to your coding agent wires all three.

* **6ms** p50 read, in-region
* **1** prompt to your coding agent
* **Free** tier, no card

## Start free

5M events a month · unlimited attributes · no card 

Work email Continue

A work address, please. We cannot provision on a personal domain.

Or [talk to an engineer](https://signals.snowplow.io/start?intent=engineer&lp=generative-ui).

[ Try it on yourself ↓ ](#live-panel) 

Below is your own visit to this page, computed by Signals as you read.

### Signals, about you 

connecting 

See live events firing as you browse this page on the left; what Signals computed about you on the right, refreshed every few seconds.

Implement this

this page · events 0 writes 

Product Solutions Developers Pricing Start free 

Start free Engineer 

this panel

the rest of the page

nothing sent yet

write 

attribute store · your session no read yet 

reading\_now 

pages\_last\_5\_min 

seconds\_since\_last\_action 

sections\_read 

seconds\_engaged 

pricing\_views 

menus\_explored 

features\_wanted 

cta\_clicks 

arrived\_from 

waiting for the first computed value… 

Your first events are in flight through a real Snowplow pipeline. Attributes appear as the stream computes them, usually within a few seconds.

hand it to your agent one prompt 

Add the Signals MCP server to Claude Code, Cursor or any MCP client, then run this. The agent adds the SDK, defines the attribute and wires the read into your own app.

$ npx plugins add snowplow/skills

> Use the Snowplow MCP server and Signals skill, then help me plan and implement a use case. Make sure everything is tested and works as intended.

Copy the prompt[How to connect the MCP server](https://docs.snowplow.io/docs/llms-support/snowplow-mcp/) 

or 

write it yourself three steps 

01 Track the event once, in your app 

trackPageView(); // browser tracker, already on this page

02 Define the attribute once, in Signals 

Attribute(name="pages_last_5_min", events=["page_view"],
  aggregation="category_count", property="page_urlpath",
  period=timedelta(minutes=5))

03 Read it back every request 

await signals.getServiceAttributes({
  name: "signals_site_session_service",
  attribute_key: "domain_sessionid",
  identifier: "…", // your session id, once set
});

Why generative UI needs live state

## A page that composes itself needs to know who it is composing for. 

Before 

### The spec describes the app, not the visitor

Route, props, cart, maybe a profile from last night. The model picks components for the average visitor because that is all the state describes, and the page comes out the same for everyone, the way a template does.

`state = { route, props }` 

With Signals 

### The visitor's session, in the state

Add a Snowplow SDK and events flow in. Name the activity the composition needs and Signals returns it as JSON, current as of this click, ready to sit beside the route in the state object.

`getAgenticContext()` 

Result 

### The spec changes with the visitor

Jev picks the compare panel for someone weighing two products and the reassurance card for someone stalled on price. json-render draws whichever it chose, from components you already have.

`spec = compose(answers)` 

What you build with it

## Pages that compose themselves around the visitor. 

Each slot in the spec is one typed question. The catalog stays yours, so the model can only pick from components you wrote, and every pick comes with a probability you can read.

### Lead with what they came for

Which section leads: the code, the numbers, the comparison or the price. Picked against what this visitor has read and skipped on this visit, and drawn from your catalog.

`choice: which section leads?` 

### Show proof in the shape they trust

A code sample for the engineer, an outcome for the PM, an assurance for the person who has been on the security page. The same catalog, a different component in the slot.

`choice: code, number, outcome or assurance?` 

### Answer the objection before it is typed

Someone who opened pricing twice and went back is asking about cost. The spec gets the pricing answer as a callout, not a link they have to find.

`choice: which objection, or none?` 

### Change the catalog, not the model

Add a component, describe it in the catalog, and the model can pick it on the next render. No retrain, no prompt engineering, one pull request.

`edit the catalog, reload` 

How it works

## State, decision, spec, render. 

Signals does the knowing. Jev does the choosing. json-render does the drawing, from a catalog only you can add to. The one-liner at the bottom of this page teaches your coding agent the whole loop.

1. 01 **Collect.** Add a Snowplow SDK to your app and behavioral events start flowing in, validated on the way.
2. 02 **Read.** One call returns what this visitor has been doing as JSON, <1s after the event, in 6ms p50.
3. 03 **Choose.** Pass it as the state on your Jev call, one typed question per slot in the page.
4. 04 **Render.** Turn the answers into a json-render spec and let it draw the components from your catalog.

Signals → your app 6ms p50 

name page\_session 

format json 

events last 30 this session 

sections\_read 4 

pricing\_views 2 

Trigger objection\_visible delivered to your app 

Demo

## See it in action. 

A storefront with no page designed in advance. The shopper browses, Signals keeps the session, Jev picks what goes in each slot, and json-render draws it from the catalog.

Silent recording, captioned on screen. The panel on the right is the state Signals served and the choices the model made from it. 1 min 19 sec 

Questions

## Before you try it

### What is json-render?

A library from Vercel for generative UI. You describe a catalog of components and their props, a model produces a JSON spec that uses only those components, and json-render draws it. The model never writes markup, so the page cannot contain anything you did not ship.

### Do I have to use json-render?

No. Jev's answers are typed values, so anything that maps a choice to a component works, from a switch statement upward. json-render is on this page because it is the shortest path from answers to a rendered page.

### Does this only work with Jev?

No. The context comes back as JSON over the REST API, the Node.js or Python SDK, or the MCP server, and as a plain string in narrative form. Anything that takes a state object or a prompt can read it. Jev is the model this page is written for because one typed question per slot, on every render, is what it is built to answer.

### Does Signals decide what to render?

No. Signals computes what the visitor is doing and hands it over. Which components go in the spec is the model's answer, and the catalog it picks from is yours.

### Do I need an event stream already?

No. Collection is part of Signals. Add a Snowplow SDK to your web, mobile or server app and events start flowing in. If you already run Snowplow, Signals reads the pipeline you have.

### What does the free tier include?

The full product against your own traffic, up to 5 million events a month, with no card and no sales call. You should see an attribute updating against your own traffic in the first session.

## Let your next page compose itself in minutes.

Paste the one-liner and the prompt below into your coding agent. The panel at the top of this page is the state your first spec would be composed from, computed from you as you read.

[Start free](https://signals.snowplow.io/start?lp=generative-ui) [Talk to an engineer](https://signals.snowplow.io/start?intent=engineer&lp=generative-ui) 

The real engine · no card · no sales call 

Paste this into your coding agent 

$ `npx plugins add snowplow/skills` Copy Copied 

Then: Add Snowplow Signals to this app. Find the page that should compose itself around the visitor. Define an agentic context for what they have been doing this session, read it as JSON and pass it as the state on one Jev typed question per slot. Turn the answers into a json-render spec against our component catalog and render it.
