# NUI callbacks: sending data from the UI to Lua

> Send data from FiveM NUI to Lua with NUI callbacks: RegisterNuiCallback in Lua, JS and C#, the fetch URL with GetParentResourceName, always calling cb, returning JSON to the page, a reusable fetchNui helper with browser mocks, and validating callbacks on the server.

Source: https://fam-tools.com/guides/fivem-nui-callbacks-fetch · FAM Tools · published 2026-09-11 · updated 2026-09-11 · about 10 min

**Short answer.** In Lua, `RegisterNuiCallback('name', function(data, cb) ... cb(result) end)`. In the page, `fetch(`https://${GetParentResourceName()}/name`, { method: 'POST', body: JSON.stringify(data) })` and read the JSON response. Always call `cb`, even on errors, or the request never resolves. Treat callback data like any client input: validate on the server before anything that matters.

## Key points

- URL: `https://<resource name>/<callback name>`, method POST, JSON body.
- `GetParentResourceName()` gives the resource name inside the page.
- Call `cb(...)` every time — with a JSON-encodable value.
- Callbacks run on the client; anything important must be re-checked on the server.

Messages go from Lua to the page; callbacks go the other way. When a player clicks “Buy”, the page makes a POST request to its own resource, Lua receives the data, does its work and answers — and the page gets that answer back as the fetch response.

## Registering the callback

*client.lua*

```lua
RegisterNuiCallback('buyItem', function(data, cb)
    if type(data.item) ~= 'string' then
        cb({ ok = false, error = 'bad item' })
        return
    end

    local ok = lib.callback.await('shop:buy', false, data.item, data.amount)
    cb({ ok = ok })
end)
```

`RegisterNuiCallback` exists in Lua, JavaScript and C#; Lua also accepts the older spelling `RegisterNUICallback`. The data arrives already parsed from JSON.

## Calling it from the page

*app.js*

```js
async function buy(item, amount) {
  const res = await fetch(`https://${GetParentResourceName()}/buyItem`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json; charset=UTF-8' },
    body: JSON.stringify({ item, amount }),
  });
  const result = await res.json();
  if (!result.ok) showError(result.error || 'Purchase failed');
}
```

## A reusable helper with browser mocks

In a normal browser (while developing) `GetParentResourceName` does not exist. A helper that detects the game and returns mock data lets you build the UI in Chrome with hot reload.

*fetchNui.ts*

```ts
const isGame = () => typeof (window as any).GetParentResourceName === 'function';

export async function fetchNui<T = unknown>(name: string, data: unknown = {}, mock?: T): Promise<T> {
  if (!isGame()) return mock as T;
  const res = await fetch(`https://${(window as any).GetParentResourceName()}/${name}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json; charset=UTF-8' },
    body: JSON.stringify(data),
  });
  return res.json();
}

// usage
const result = await fetchNui<{ ok: boolean }>('buyItem', { item: 'water', amount: 2 }, { ok: true });
```

## JavaScript and C# client scripts

*client.js*

```js
RegisterNuiCallback('buyItem', (data, cb) => {
  if (typeof data.item !== 'string') return cb({ ok: false });
  emitNet('shop:buy', data.item, data.amount);
  cb({ ok: true });
});
```

## Callbacks are client input

> **Anyone can call your callbacks** — Players can open the NUI devtools and send any request to your callbacks. A callback that triggers `shop:buy` with a price from the page is an exploit. Send only what the player chose; the server decides prices and checks everything — see [secure server events](https://pityus.net/guides/fivem-secure-server-events).

## Common problems

| Symptom | Cause |
| --- | --- |
| Request stays pending forever | `cb` never called on some code path |
| Request fails immediately | Wrong resource name in the URL, or no callback registered under that name |
| `GetParentResourceName is not defined` | Running in a normal browser — use the mock helper |
| `Unexpected end of JSON input` | The page calls `res.json()` but `cb` returned nothing JSON-like — return a table or string |

## Questions

### How do I send data from NUI to Lua?

POST to `https://${GetParentResourceName()}/<name>` from the page and handle it with `RegisterNuiCallback` in Lua.

### Why does my NUI fetch never finish?

The Lua callback did not call `cb`. Every path, including errors, must call it.

### Can I return data to the page?

Yes. Whatever you pass to `cb` is JSON-encoded and becomes the fetch response.

### Are NUI callbacks secure?

No more than any client input. Players can call them from devtools, so validate on the server.

## Related

- https://fam-tools.com/guides/fivem-getparentresourcename-nui-callbacks
- https://fam-tools.com/guides/fivem-sendnuimessage-patterns
- https://fam-tools.com/guides/fivem-nui-basics
- https://fam-tools.com/guides/fivem-nui-focus-and-cursor
- https://fam-tools.com/guides/fivem-nui-devtools-debugging
- https://fam-tools.com/guides/fivem-loading-screen-react-vite
