Skip to content

Call endpoints from extension UI

It’s possible to make requests to endpoints from your extension’s UI. This is useful if you want to populate your UI with dynamic data or integrate with third-party APIs.

For example, you can:

  • create or update environment variables
  • retrieve and update data in third-party APIs
  • update the installed extension’s configuration

To support this, we make an access token available to callback functions that you can use in calls to the Netlify API. If your extension allows users to authenticate using an OAuth identity provider, your endpoints have access to that OAuth token as well.

The following example adds an endpoint and updates a surface to render dynamic data retrieved from that endpoint.

  1. Create an endpoint under /src/endpoints/ that returns some data for use in your extension UI:

    src/endpoints/hello-world.ts
    import { withNetlifySDKContext } from "@netlify/sdk/ui/functions";
    export default withNetlifySDKContext((req, context) => {
    return Response.json({ data: { greeting: "Hello, world!" } });
    });
  2. Next, update your SiteNotificationsConfiguration surface to query your new hello-world endpoint for data:

    src/surfaces/SiteNotificationsConfiguration.tsx
    import { useEffect, useState } from "react";
    import { useNetlifyExtensionUIFetch } from "@netlify/sdk/ui/react";
    import { SiteNotificationsConfigurationSurface } from "@netlify/sdk/ui/react/components"
    export const SiteNotificationsConfiguration = () => {
    const fetch = useNetlifyExtensionUIFetch();
    const [greeting, setGreeting] = useState("Hello, there!");
    useEffect(() => {
    fetch("/.netlify/functions/hello-world")
    .then(async (res) => {
    const body = await res.json();
    setGreeting(body.data.greeting);
    });
    }, []);
    return (
    <SiteNotificationsConfigurationSurface>
    <div>
    {greeting}
    </div>
    </SiteNotificationsConfigurationSurface>
    );
    };

    Don’t use the global fetch function to perform requests to endpoints

    Note that this example uses the fetch implementation provided by the SDK through useNetlifyExtensionUIFetch rather than the global fetch. The SDK fetch implementation ensures all of the necessary headers are set so that you can make authenticated calls to your endpoint.

From here, you can add more complex behavior to your endpoints, add a form and collect information from a user, and more.

tRPC integration

The Netlify SDK includes an optional integration with tRPC, a community-maintained solution for writing queries that offer end-to-end type safety.

By default, extensions created by running npm create @netlify/sdk@latest include all the boilerplate necessary to write tRPC procedures. You can write new procedures and call them from your extension UI. For an overview of the boilerplate files, refer to the endpoints tRPC integration documentation.

You can update the boilerplate src/server/router.ts file to add new procedures to your tRPC application router:

src/server/router.ts
import { type Context } from "@netlify/sdk/ui/functions/trpc";
import { router } from "./trpc.js";
export type AppRouter = typeof appRouter;
export const appRouter = router({
myCoolQuery: procedure.query(async ({ ctx }) => {
const { client } = ctx;
// Use the Netlify SDK client to do cool stuff here
return { greeting: "Hey there!" };
}),
});

You can then query this new procedure from components in your extension UI:

src/ui/surfaces/TeamConfiguration.tsx
import { Card, CardTitle, TeamConfigurationSurface } from "@netlify/sdk/ui/react/components";
import { trpc } from "../trpc.js";
export const TeamConfiguration = () => {
const myCoolQuery = trpc.myCoolQuery.useQuery();
return (
<TeamConfigurationSurface>
<Card>
<CardTitle>Hello, World!</CardTitle>
<p>This is my extension’s team configuration surface.</p>
<p>{myCoolQuery.data?.greeting}</p>
</Card>
</TeamConfigurationSurface>
);
};

Next steps

You should now have an extension that appears in multiple locations in the Netlify UI, includes an endpoint that returns dynamic data, and then renders dynamic data to users.

From here, you can continue to add more to your extension. When you’re ready you can take the next steps to publish your extension for others to find and use.

Got it!

Your feedback helps us improve our docs.