---
agentTools:
  projectIndex: https://developers.pipefy.com/llms.txt
---

# Client SDK overview

Loading the SDK, and the difference between initCall() and init()

Use the Client SDK to interact with our Apps framework directly from your iframe. The SDK provides a `PipefyApp` global that handles cross-frame communication between your app and the host Pipefy product.

## Getting the SDK

Load it from `https://platform.staticpipefy.com/pipefy-app.js`:

```html
<script src="https://platform.staticpipefy.com/pipefy-app.js"></script>
```

The SDK is distributed as a plain script that defines a `window.PipefyApp` global. It is not published to npm, so bundlers cannot import it — load it with a script tag and read it off `window`. In a framework app, that means guarding on its presence rather than importing it:

```javascript
if (window.PipefyApp) {
  const p = window.PipefyApp.init();
}
```

Every page of your app that needs a client — the entry point, plus each sidebar, modal, dropdown and tab page — needs this script tag.

> ⚠️ Apps only run inside Pipefy
>
> Pipefy appends an `appID` query parameter when it builds your iframe, and the SDK needs it. Opening your app's URL directly in a browser tab throws:
>
> `PipefyApp: no "appID" query parameter found on this page. This app must be opened from within Pipefy, not by navigating to the app URL directly.`
>
> This is the most common surprise when testing locally. To exercise your app, register it against your local URL and open it from within Pipefy — see [Introduction](https://developers.pipefy.com/docs/build-your-first-pipefy-app).

## Two ways to start

There are two entry points, and which one you call depends on which page of your app is running.

### `PipefyApp.initCall(features)` — your entry point

The page at your manifest's `init_url` is loaded once, hidden, and its only job is to declare what your app adds to Pipefy. Call `initCall()` with one handler per [feature](https://developers.pipefy.com/docs/features):

```javascript
PipefyApp.initCall({
  'pipe-buttons': function (p, pipe) {
    return [
      {
        text: 'Sprint',
        callback: function (p) {
          p.sidebar({ title: 'Sprint', url: './sprints/new' });
        },
      },
    ];
  },
});
```

Each handler receives a client and returns a description of what to render — see the individual feature pages for the exact shape each one expects. `initCall()` also initialises the client internally, so you do not call `init()` first.

This works **only** on the `init_url` page. Calling it from a sidebar or tab page does nothing.

### `PipefyApp.init()` — every other page

The pages you render *inside* a dropdown, modal, tab, sidebar or pipe view are separate documents in separate iframes. Each one gets its own client:

```javascript
var p = PipefyApp.init();

p.card().then(function (card) {
  document.getElementById('title').textContent = card.title;
});
```

`init()` returns the client object — the `p` you see throughout these docs. It is safe to call more than once on the same page; the second call returns the existing client rather than building a new one. If you need the client from a module that did not call `init()`, use `PipefyApp.client()`.

### Which to use

| Your page is…                | Call                        | Then                                                                                               |
| :--------------------------- | :-------------------------- | :------------------------------------------------------------------------------------------------- |
| The `init_url` entry point   | `PipefyApp.initCall({...})` | Nothing else. It renders no UI.                                                                    |
| A card tab or pipe view      | `PipefyApp.init()`          | **Must** also call [`PipefyApp.render()`](https://developers.pipefy.com/docs/user-interface-functions#pipefyapprendercallback)    |
| A modal, dropdown or sidebar | `PipefyApp.init()`          | Optionally [`PipefyApp.resizeTo('#root')`](https://developers.pipefy.com/docs/user-interface-functions#pipefyappresizetoselector) |

The client is the same object in all cases. What differs is the set of `PipefyApp.*` helpers available to that surface — see [Where each function works](https://developers.pipefy.com/docs/sdk-availability).

## A note on `p`

`p` is just the conventional name for the client, used consistently across these docs and the sample apps. Feature callbacks receive it as their first argument, so you will often see it shadowed:

```javascript
PipefyApp.initCall({
  'card-buttons': function (p, pipe) {   // p for the root frame
    return [{
      text: 'Open',
      callback: function (p) {           // p for the click context
        p.modal({ url: './modal.html', width: '70%', height: '70%' });
      },
    }];
  },
});
```

Use the `p` your callback was handed rather than one captured from an outer scope.

## Next

* [Get Pipefy data](https://developers.pipefy.com/docs/get-pipefy-data) — read the current card, pipe and fields
* [Make API calls](https://developers.pipefy.com/docs/make-api-calls) — the full GraphQL API
* [Custom App Data](https://developers.pipefy.com/docs/store-retrieve-custom-data) — store your own data
* [User Interface functions](https://developers.pipefy.com/docs/user-interface-functions) — sidebars, modals, dropdowns
* [Where each function works](https://developers.pipefy.com/docs/sdk-availability) — mount-point availability