npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@flotiq/nextjs-live-preview

v0.7.1

Published

Support for live preview in Next.JS framework in flotiq-api-sdk

Readme

@flotiq/nextjs-live-preview

A comprehensive Next.js integration for Flotiq CMS that provides real-time live preview functionality through WebSocket connections. This package allows content editors to see their changes in real-time as they edit content in the Flotiq CMS.

Features

  • 🔄 Real-time content updates via WebSocket connections
  • 👥 Multi-user editing indicators showing who's currently editing each field
  • 🎯 Auto-scroll to active fields when editors focus on content
  • 🔗 Relation field hydration supporting 2 levels of hydration
  • 🏷️ Smart relation cache invalidation with Next.js cache tags
  • 📱 Flotiq iframe support for seamless CMS integration
  • Throttled updates to prevent excessive re-renders
  • 🎨 Customizable UI components for editor indicators

Installation

npm install @flotiq/nextjs-live-preview

Requirements

  • React: 19.0.0 or higher
  • Next.js: 15.0.0 or higher
  • Flotiq API SDK: 0.6.0 or higher

How It Works

  1. WebSocket Connection: The middleware establishes WebSocket connections to Flotiq's real-time servers
  2. Content Interception: API requests for content objects are intercepted and enhanced with live data
  3. Real-time Updates: Changes from the CMS are pushed via WebSocket and trigger React re-renders
  4. Editor Awareness: Multiple editors' activities are tracked and displayed with colored indicators

Quick Start

1. Configure the Middleware

Add the live preview middleware to your Flotiq API configuration:

import { Flotiq } from "@flotiq/flotiq-api-sdk";
import { createNextLivePreviewMiddleware } from "@flotiq/nextjs-live-preview";

const api = new Flotiq({
  middleware: [createNextLivePreviewMiddleware()],
});

Function createNextLivePreviewMiddleware supports provided options:

  • flotiqApiKey - optional. It uses FLOTIQ_API_KEY env by default. It can be used to override Flotiq API key
  • connectionMode - optional. Possible options: ws or http. It uses ws mode by default. It is connection mode used by server. More about connetion modes

2. Create Live Preview API Route

Create the API route that handles live preview mode toggling in app/api/flotiq/live-preview/route.ts file.

import { NextRequest } from "next/server";
import { redirect } from "next/navigation";
import { livePreview } from "@flotiq/nextjs-live-preview/server";

export async function GET(req: NextRequest) {
  const redirectPath = req.nextUrl.searchParams.get("redirect") || "/";

  /**
   * Validate the request. 
   * 
   * To validate the request you can use the `Client Authoristion Key` passed to the live preview URL from **Live Preview** plugin as `editor_key` URL param. 
   * Make sure to define it in your application's environment variables and passed the same `Client Authoristion Key` to the plugin settings.
   * Without validating this key, everybody could see your latest data.
   * 
   * Example validation:
   * 
   * const clientAuthKey = req.nextUrl.searchParams.get('editor_key');
   * if (clientAuthKey !== process.env.FLOTIQ_CLIENT_AUTH_KEY) {
   *   return new Response('Unauthorized', { status: 401 });
   * }
   */

  const livePreviewState = await livePreview();
  const newLivePreview = req.nextUrl.searchParams.has("live-preview")
    ? req.nextUrl.searchParams.get("live-preview") === "true"
    : !livePreviewState.isEnabled;

  if (newLivePreview) {
    livePreviewState.enable(req);
  } else {
    livePreviewState.disable();
  }

  redirect(redirectPath);
}

3. Add Live Preview Status Component

This component is need for router to refresh to see latest data. It is adding the banner with live preview informations. If you don't want to use predefined banner, you can use useLivePreviewStatus hook and create your own component (more info).

import { livePreview } from "@flotiq/nextjs-live-preview/server";
import { LivePreviewStatus } from "@flotiq/nextjs-live-preview/client";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const { isEnabled } = await livePreview();

  return (
    <html>
      <body>
        <main>
          {isEnabled && (
            <LivePreviewStatus editorKey={process.env.FLOTIQ_EDITOR_KEY} />
          )}
          {children}
        </main>
      </body>
    </html>
  );
}

4. Cache Revalidation Route (Required for HTTP Mode)

When using HTTP mode, you need to create an additional API route for cache revalidation. Without this route, relation fields will retain their cache from the first visit and data won't update properly.

Create a file at app/api/flotiq/live-preview/revalidate/route.ts:

import { NextRequest } from 'next/server';
import { livePreview } from '@flotiq/nextjs-live-preview/server';

export async function POST(req: NextRequest) {
  const contentType = req.nextUrl.searchParams.get('content_type') || '';
  const id = req.nextUrl.searchParams.get('id') || '';

  const { clearCache } = await livePreview();
  clearCache(contentType, id);

  return new Response('Live preview cache cleared', { status: 200 });
}

This route calls the clearCache method from the live preview package. The method checks if live preview is enabled, and if not, nothing happens.

After creating this route, pass its URL to the LivePreviewStatus component or useLivePreviewStatus hook:

<LivePreviewStatus 
  editorKey={process.env.FLOTIQ_EDITOR_KEY}
  revalidateUrl="/api/flotiq/live-preview/revalidate"
/>

When relation fields change, the frontend will send a fetch request to this route if the URL is provided. If not provided, nothing happens.

Note: The WebSocket (ws) mode clears the cache on the server side automatically, so this route is not required for ws mode. However, you can still use it if you want to perform additional actions when relations change.

You can also add custom parameters to the URL if needed, for example:

revalidateUrl="/api/flotiq/live-preview/revalidate?my_param=test"

Server Connection Modes

WebSocket Mode (Recommended)

It uses persistent connections to websocket.

How it works:

  1. The middleware and frontend component establish WebSocket connections to Flotiq's real-time servers.
  2. When editing content object, Flotiq Live Preview plugin sends information to the application.
  3. API requests for content objects are intercepted and enhanced with live data in middleware.
  4. Frontend component is refreshing the router so that the latest data can be seen.

HTTP Mode

It uses persistent connections to websocket only in frontend component. But the middleware is not. This method allows using live preview in deployed application where the connection cannot be persistent for the server, eg. Vercel.

How it works:

  1. The frontend component establish WebSocket connections to Flotiq's real-time servers.
  2. When editing content object, Flotiq Live Preview plugin sends information to the frontend component.
  3. Middleware intercepts API requests for content objects and fetches newset data from special enpoint prepared in webscoket for getting latest data.
  4. Frontend component is refreshing the router so that the latest data can be seen.

Advanced Usage

Live Preview Boxes for Field Editing

Wrap your content fields with LivePreviewBox to show visual editing indicators and enable field-specific interactions:

import { LivePreviewBox } from "@flotiq/nextjs-live-preview/server";

export default async function BlogPost({
  params,
}: {
  params: { slug: string };
}) {
  const post = await flotiqApi.ContentBlogpostAPI.get(params.slug, {
    hydrate: 1,
  });

  return (
    <article>
      <LivePreviewBox objectId={post.id} ctdName="blogpost" fieldName="title">
        <h1>{post.title}</h1>
      </LivePreviewBox>
    </article>
  );
}

Custom Live Preview Hook

If you doesn't want to use LivePreviewStatus component, you can use useLivePreviewStatus hook. This hook is doing refreshes to the router on data update.

Exmaple code with custom banner:

"use client";

import { useLivePreviewStatus } from "@flotiq/nextjs-live-preview/client";

export function CustomLivePreviewIndicator() {
  const { isConnected, updatedTime, contentType, objectId } =
    useLivePreviewStatus();

  if (!isConnected) return null;

  return (
    <div className="live-preview-custom">
      <span>
        Editing {contentType}#{objectId}
      </span>
      {updatedTime && <span>Last update: {updatedTime}</span>}
    </div>
  );
}

Configuration Options

Middleware Options

interface NextLivePreviewMiddlewareOptions {
  /**
   * Flotiq API key for authorization
   * @default process.env.FLOTIQ_API_KEY
   */
  flotiqApiKey?: string;
  /**
   * Connection mode for live preview data
   * - "ws": Active WebSocket connection (default, recommended)
   * - "http": HTTP polling from WebSocket server
   */
  connectionMode?: "ws" | "http";
}

LivePreviewBox Props

interface LivePreviewBoxProps {
  /** Field content to wrap */
  children: React.ReactNode;
  /** Field name in the content object */
  fieldName: string;
  /** Content object ID */
  objectId: string;
  /** Content Type Definition name */
  ctdName: string;
  /** Scroll offset for auto-focus (default: 0) */
  scrollTopOffset?: number;
  /** Use light color theme for editor indicators (default: false) */
  lightColors?: boolean;
  /** Additional CSS class name */
  className?: string;
}

LivePreviewStatus Props

interface LivePreviewStatusProps {
  /** Client Authorization key */
  editorKey: string;
  /** URL to cache revalidation route (required for HTTP mode) */
  revalidateUrl?: string;
  /** Additional CSS class name */
  className?: string;
}

Troubleshooting

  • Ensure cookies are enabled in your browser
  • Check that the API route is correctly implemented
  • Verify the Client Authorisation Key matches in both Flotiq and application
  • Verify if deployed application is allowing persistent connections. Otherwise change the connection mode to http method