npm package: @struct-app/nextjs
Description: ##  Installation
Latest version: 0.2.2

# Struct Next.js SDK

##  Installation

```bash
 npm install --save @struct-app/nextjs
```

## Setup

### 1. Wrap your Next Config with `withStruct`

This will configure the Struct SDK for use with your Next.js app. By default `withStruct` will proxy all requests to `/struct-proxy/:path` to the Struct API meaning that you don't need to worry about requests to Struct being blocked by ad-blockers or tracker-blockers. You can customise the proxy path by passing `proxyBasePath` to the `withStruct` function, or you can disable the proxy by passing `proxy: false` to the `withStruct` function.

```JS
// next.config.mjs

import { withStruct } from "@struct-app/nextjs";


const config = {
 // Your Next.js config
}

export default withStruct({
 apiKey: 'YOUR_API_KEY'
})(config)
```

### 2. Create Client and Server-Side Struct Instances

#### Client Side

Create a `client.ts` file in your `lib/struct` directory. This file will be used to create a React Context Provider and a React Hook for accessing the Struct client. Be sure to remember to add `use client` to the top of the file.

```TS
// lib/struct/client.ts
"use client"

import { createStruct } from "@struct-app/nextjs/client";

export const { StructProvider, useStruct, StructIdentityProvider } = createStruct();
```

#### Server Side

Create a `server.ts` file in your `lib/struct` directory. This file will be used to create a server-side client for tracking events from within server actions / API routes.

`createStruct` returns `track` and `trackAsync` functions for tracking events on the server side.

```TS
// lib/struct/server.ts
import { createStruct } from "@struct-app/nextjs/server";
import { getUser } from "your-auth-library";

export const { track, trackAsync } = createStruct();
```

#### TypeScript Integration

If you are using TypeScript, you can create types for your events and traits by passing generic types for your events and traits to `createStruct`.

```TS
// lib/struct/types.ts
import type { event, traits } from "@struct-app/nextjs";

export type StructEvents = {
  my_event: event<{
    foo: string;
  }>;
  purchase_success: event<{
    value: number;
    currency: string;
  }>;
  feedback: event<{
    feedback: string;
  }>;
}

export type StructTraits = traits<{
  foo: string;
  type: "premium" | "free";
  age: number;
}>
```

```TS
// lib/struct/client.ts
import { createStruct } from "@struct-app/nextjs/client";

import type { StructEvent, StructTraits } from "./types";

export const { StructProvider, useStruct, StructIdentityProvider } = createStruct<StructTraits, StructEvents>();

```

```TS
// lib/struct/server.ts
import { createStruct } from "@struct-app/nextjs/server";

import type { StructEvent, StructTraits } from "./types";

export const { track, trackAsync } = createStruct<StructTraits, StructEvents>();
```

### 3. Wrap your App with the `StructProvider`

Wrap your app with the `StructProvider` so you can use the `useStruct` hook to access the Struct client anywhere in your app. Page views will be tracked automatically by default.

> You can disable automatic page view tracking by passing `disablePageTracking` to `StructProvider`.

```tsx
// app/layout.tsx
import type { ReactNode } from "react";

import { StructProvider } from "./lib/struct/client";

interface LayoutProps {
  children: ReactNode;
}
export default function Layout({ children }: LayoutProps) {
  return (
    <html lang="en">
      <body>
        <StructProvider>{children}</StructProvider>
      </body>
    </html>
  );
}
```

### 4. Setup Identity Tracking with the `StructIdentityProvider`

To identify users and organisations, you can use the `StructIdentityProvider` component. This will automatically identify users and their organisations when the component mounts and will update the user and organisation when the props change. You can optionally pass `traits` to the `StructIdentityProvider` to include additional traits about the user.

```tsx
// app/StructIdentityTracker.tsx

import { getUser } from "your-auth-library";

import { StructIdentityProvider } from "./lib/struct/client";

export default function StructIdentityTracker() {
  const user = getUser(); // Your user object from your auth provider

  return (
    <StructIdentityProvider
      userId={user.id ?? null}
      name={user.name}
      email={user.email}
      organisationId={user.organisationId}
      organisationName={user.organisationName}
      traits={{ foo: "bar", type: "premium", age: 30 }}
    />
  );
}
```

```tsx
// app/layout.tsx
import type { ReactNode } from "react";

import { StructProvider } from "@struct-app/nextjs/client";

import StructIdentityTracker from "./StructIdentityTracker";

interface LayoutProps {
  children: ReactNode;
}

export default function Layout({ children }: LayoutProps) {
  return (
    <html lang="en">
      <body>
        <StructProvider>
          <StructIdentityTracker />
          {children}
        </StructProvider>
      </body>
    </html>
  );
}
```

## Usage

### Track Events (Client Side)

```tsx
// app/MyComponent.tsx

"use client";

import { useStruct } from "./lib/struct/client";

export default function MyComponent() {
  const struct = useStruct();

  function handleClick() {
    struct.track("my_event", { foo: "bar" }); // Track custom events
    struct.track("purchase_success", { value: 1000, currency: "USD" }); // Track a purchase of $10
  }

  return <button onClick={handleClick}>Click Me</button>;
}
```

### Track Events (Server Side)

Using the `track` function, you can track events on the server side and from within server actions. You can optionally pass a `userId` to associate the event with a user and their current session.

```tsx
// app/feedback/page.tsx

import { redirect } from "next/navigation";
import { getAuth } from "your-auth-library";

import { track } from "./lib/struct/server";

function FeedbackPage() {
  const submitForm = (formData: FormData) => {
    "use server";

    const user = getAuth();

    const feedback = formData.get("feedback") as string;

    track("feedback", { feedback }, { userId: user.id });

    redirect("/feedback/thank-you");
  };

  return (
    <form action={submitForm}>
      <h2>Feedback and Tips</h2>
      <textarea name="feedback" />
      <button type="submit">Submit</button>
    </form>
  );
}
```