Skip to main content

Next.js SDK Usage - Pages Router

Npm package version GitHub

Usage

Wrap your App in the DevCycle Higher-Order Component

In your _app.tsx file, wrap the App component in the DevCycle Higher-Order Component:

// _app.tsx
import React from 'react'
import type { AppProps } from 'next/app'
import { appWithDevCycle } from '@devcycle/nextjs-sdk/pages'

function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

export default appWithDevCycle(MyApp)

In each page in your App where you are using DevCycle, hook up the server-side helper to retrieve configuration on the server and allow for server-side rendering using the same user data as the client:

import { GetServerSideProps } from 'next'
import { getServerSideDevCycle } from '@devcycle/nextjs-sdk/pages'

export const getServerSideProps: GetServerSideProps = async (context) => {
// get the user identity serverside. Replace with your own function for determining your user's identity
const user = {
user_id: 'server-user',
}
return {
props: {
...(await getServerSideDevCycle({
serverSDKKey: process.env.DEVCYCLE_SERVER_SDK_KEY || '',
clientSDKKey: process.env.NEXT_PUBLIC_DEVCYCLE_CLIENT_SDK_KEY || '',
user,
context,
})),
},
}
}

This helper will retrieve the DevCycle configuration and pass it to the rest of the component tree. It will bootstrap DevCycle on the client browser with the same configuration used by the server, allowing for faster page rendering and matching hydration of client-rendered and server-rendered content.

From this point, usage becomes the same as the DevCycle React SDK. Refer to the documentation for that SDK.

The same hooks used in that SDK are re-exported from this SDK.

For example, to retrieve a variable value in a component:

import { useVariableValue } from '@devcycle/nextjs-sdk/pages'
import * as React from 'react'

export const MyComponent = () => {
const myVariable = useVariableValue('myVariable', false)
return myVariable ? <NewComponent /> : <OldComponent />
}

Static Rendering

If your page uses static rendering instead, you can use the static version of the DevCycle helper:

import { GetStaticProps } from 'next'

export const getStaticProps: GetStaticProps = async () => {
// get the user identity serverside. Replace with your own function for determining your user's identity
const user = {
user_id: 'server-user',
}
return {
props: {
...(await getStaticDevCycle({
serverSDKKey: process.env.DEVCYCLE_SERVER_SDK_KEY || '',
clientSDKKey: process.env.NEXT_PUBLIC_DEVCYCLE_CLIENT_SDK_KEY || '',
user,
})),
},
}
}

The static version of the helper still retrieves the DevCycle configuration and allows for client bootstrapping. However, it omits features that rely on the dynamic request information to work. This includes:

  • automatic determination of the platform version based on the user agent of the request. Targeting by this property in the DevCycle platform will be unavailable.

EdgeDB

note

EdgeDB support requires Next.js SDK version 2.23.4 or higher.

EdgeDB allows you to save user data to our EdgeDB storage so that you don't have to pass in all the user data every time you identify a user.

To get started, enable EdgeDB on your project by following the guide here.

info

Enabling EdgeDB will switch the SDK to use client-side bucketing instead of local server-side bucketing. This may result in a slightly increased latency for variable evaluations.

Once you have EdgeDB enabled in your project, pass in the enableEdgeDB option to turn on EdgeDB mode for the SDK:

import { GetServerSideProps } from 'next'
import { getServerSideDevCycle } from '@devcycle/nextjs-sdk/pages'

export const getServerSideProps: GetServerSideProps = async (context) => {
// get the user identity serverside. Replace with your own function for determining your user's identity
const user = {
user_id: 'test_user',
customData: { amountSpent: 50 },
}
return {
props: {
...(await getServerSideDevCycle({
serverSDKKey: process.env.DEVCYCLE_SERVER_SDK_KEY || '',
clientSDKKey: process.env.NEXT_PUBLIC_DEVCYCLE_CLIENT_SDK_KEY || '',
user,
context,
options: { enableEdgeDB: true },
})),
},
}
}

This will send a request to our EdgeDB API to save the custom data under the user test_user.

In the example, amountSpent is associated to the user test_user. In your subsequent requests for the same user_id, you may omit any of the data you've sent already as it will be pulled from the EdgeDB storage when segmenting to experiments and features:

export const getServerSideProps: GetServerSideProps = async (context) => {
const user = {
user_id: 'test_user', // no need to pass in "amountSpent" anymore!
}
return {
props: {
...(await getServerSideDevCycle({
serverSDKKey: process.env.DEVCYCLE_SERVER_SDK_KEY || '',
clientSDKKey: process.env.NEXT_PUBLIC_DEVCYCLE_CLIENT_SDK_KEY || '',
user,
context,
options: { enableEdgeDB: true },
})),
},
}
}

Feature Opt-In

note

Feature Opt-In support requires Next.js SDK version 2.25.0 or higher.

Feature Opt-In gives your end-users the ability to turn on/off Features for themselves. Learn more on how to turn on Feature Opt-In here.

Once Feature Opt-In is enabled, the DevCycle Next.js SDK will fetch from the Client SDK API instead of fetching a static config from our CDN. It only does this if a user is found to have Feature Opt-In records already. Because of this, users that have Opt-In records will see a slight increase in latency in getting a config.

DevCycleUser Object

DevCycleUser Typescript Schema

PropertyTypeDescriptionAuto-Populated
isAnonymousBooleanBoolean to indicate if the user is anonymous. Automatically true if user_id is not provided.-
user_idStringUnique user IDNo
emailStringUser's emailNo
nameStringUser's nameNo
languageStringUser's languageNo
countryStringUser's countryNo
appVersionStringApp versionNo
appBuildNumberApp buildNo
customDataDVCJSONKey/value map of properties to be used for targetingNo
privateCustomDataDVCJSONKey/value map of properties to be used for targeting. Private properties will not be included in event logging.No
platformStringPlatform/OSYes
platformVersionStringPlatform/OS VersionYes
deviceModelStringUser AgentYes

Initialization Options

The SDK exposes various initialization options which can be set by passing a DevCycleOptions object in the appWithDevCycle method:

DevCycleOptions Typescript Schema

DevCycle OptionTypeDescription
loggerDevCycleLoggerLogger override to replace default logger
logLevelDevCycleDefaultLogLevelSet log level of the default logger. Options are: debug, info, warn, error. Defaults to info.
eventFlushIntervalMSNumberControls the interval between flushing events to the DevCycle servers in milliseconds, defaults to 10 seconds.
flushEventQueueSizeNumberControls the maximum size the event queue can grow to until a flush is forced. Defaults to 100.
maxEventQueueSizeNumberControls the maximum size the event queue can grow to until events are dropped. Defaults to 1000.
apiProxyURLStringAllows the SDK to communicate with a proxy of DevCycle bucketing API / client SDK API.
disableRealtimeUpdatesBooleanDisable Realtime Updates
disableAutomaticEventLoggingBooleanDisables logging of sdk generated events (e.g. variableEvaluated, variableDefaulted) to DevCycle.
disableCustomEventLoggingBooleanDisables logging of custom events, from track() method, and user data to DevCycle.
enableEdgeDBBooleanEnables EdgeDB to save and retrieve user data from EdgeDB storage