Embedded components
Drop read-only donations, donors, and payouts tables into your product with a component session and three custom elements.
Show a connected organization's donations, donors, or payouts inside your own product without building tables or wiring the API yourself. Your backend mints a short-lived component session; the browser renders custom elements that fetch, paginate, and style themselves, like Stripe Connect's embedded components.
Prerequisites
- Your app is connected to the organization through OAuth, or you hold the org's API key.
- The credential holds the read scope behind each component you want:
donations:readfor donations,donors:readfor donors,payouts:readfor payouts. @givebear/connect0.2.0 or later in the browser bundle.
Steps
Mint a component session on your backend
Call POST /component-sessions with the components your page renders. The
session's browser token can only read those resources, and only if your own
credential could.
curl -X POST "https://givebear.io/api/v1/component-sessions" \
-H "Authorization: Bearer gb_live_..." \
-H "Content-Type: application/json" \
-d '{ "components": ["donations", "payouts"] }'import { GivebearConnect } from "@givebear/connect";
const gb = new GivebearConnect({ token: "gb_live_..." });
const session = await gb.componentSessions.create({
components: ["donations", "payouts"],
});
// session.token is returned only once. Send it to your frontend.import requests
session = requests.post(
"https://givebear.io/api/v1/component-sessions",
headers={"Authorization": "Bearer gb_live_..."},
json={"components": ["donations", "payouts"]},
).json()<?php
$ch = curl_init("https://givebear.io/api/v1/component-sessions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer gb_live_...",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"components" => ["donations", "payouts"],
]));
$session = json_decode(curl_exec($ch), true);
curl_close($ch);require "net/http"
require "json"
uri = URI("https://givebear.io/api/v1/component-sessions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer gb_live_..."
request["Content-Type"] = "application/json"
request.body = { components: ["donations", "payouts"] }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
session = JSON.parse(response.body)body := strings.NewReader(`{ "components": ["donations", "payouts"] }`)
req, _ := http.NewRequest("POST", "https://givebear.io/api/v1/component-sessions", body)
req.Header.Set("Authorization", "Bearer gb_live_...")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)The response includes token (gbct_...) exactly once, plus components
and expires_at. Sessions expire after one hour and are reusable until then,
so page reloads keep working. Mint a fresh session per page view; do not
store tokens.
Render the components
Import the components module once (it registers the custom elements), then place elements with the session token. Each element renders its own loading, empty, and error states, plus a "Load more" pager.
<script type="module">
import "@givebear/connect/components";
</script>
<givebear-donations session="gbct_..."></givebear-donations>
<givebear-payouts session="gbct_..." limit="5"></givebear-payouts>import "@givebear/connect/components";
export function DonationsPanel({ token }: { token: string }) {
return (
<>
<givebear-donations session={token} />
<givebear-payouts session={token} limit="5" />
</>
);
}Using TypeScript with React? Declare the elements once (for example in globals.d.ts) so JSX accepts them:
type GivebearElementProps = React.HTMLAttributes<HTMLElement> & {
session: string;
limit?: string;
"base-url"?: string;
};
declare global {
namespace React.JSX {
interface IntrinsicElements {
"givebear-donations": GivebearElementProps;
"givebear-donors": GivebearElementProps;
"givebear-payouts": GivebearElementProps;
}
}
}Handle expiry
When the session expires the element shows a notice and dispatches a bubbling
givebear:session-expired event. Listen for it, mint a fresh session on your
backend, and update the session attribute; the element reloads itself.
document.addEventListener("givebear:session-expired", async () => {
const { token } = await fetch("/api/my-givebear-session").then((r) => r.json());
for (const el of document.querySelectorAll("[session]")) {
el.setAttribute("session", token);
}
});Elements and attributes
| Element | Shows | Needs scope |
|---|---|---|
<givebear-donations> | Donor, fund, amount (with a recurring pill), date | donations:read |
<givebear-donors> | Name, email, location, date added | donors:read |
<givebear-payouts> | Amount, status, initiated and arrival dates | payouts:read |
Every element takes the same attributes.
| Attribute | Meaning |
|---|---|
session | The component session token (gbct_...). Required. |
limit | Rows per page, 1 to 100 (default 10). |
base-url | API origin override (default https://givebear.io). |
Failures other than expiry dispatch a bubbling givebear:error event with
detail.message and, for HTTP errors, detail.status.
Theming
The elements render in an isolated shadow root with a neutral look. Override CSS custom properties on the element or any ancestor:
givebear-donations {
--givebear-font: "Inter", sans-serif;
--givebear-accent: #7c3aed;
--givebear-fg: #1c1917;
--givebear-muted: #78716c;
--givebear-border: #e7e5e4;
--givebear-bg: #ffffff;
--givebear-radius: 8px;
}How the security model works
The browser token is read-only by construction: its scopes are derived from
the requested components (all *:read), capped by what your backend
credential holds, and it cannot mint further sessions. It expires after one
hour. Donor names and emails are visible to whoever holds the token, so only
render these components to users who should see the organization's data.
Related
Embedded donations
Collect donations inside your product with an embed session.
API reference
The full component-sessions request and response schema.
Authentication
OAuth apps, API keys, and scopes.
Webhooks
React to new donations instead of polling.