Unable to view sharable link to a non prismic user

I tried all other repos which are not using the @prismicio/next and none of them are working... Any idea of how to make it work?

1 Like

@Pau Are there any updates on this? Were you able to replicate it?

No news for the moment @kris. I'll update this thread as soon as there are any.

@Pau What can I do to fix this? My client needs to use sharable previews.

Have you tried replicating this? It should be relatively straightforward to replicate given that non of the websites which I manage don't have a working sharable preview

Is there anyone on the support team that can help me with fixing this bug?

Hi Kristiyian,

I'm reaching out to the team now to get you a response. Sorry about the delay in the reply to this.

Thanks.

@Phil Any updates on when a fix might be released?

Hi Jiro,

There are no updates for this one yet, unfortunately.

Hey @Phil, my clients can't really communicate successfully at the moment since the share feature is not working for them. I let them know that the Prismic team is looking into it, but that was over a month ago. Are there any suggestions on how to approach this problem?

@Phil I keep seeing replies to this thread. It sounds like lots of others are having the same issue but no ETA for a fix. It seems like this is not high on your engineering teams list, but its pretty high on your users priority list. This is a feature that most other headless CMS's have.

Hey Everyone,

So I checked with the team, and anonymous share links work with Next.js when set up with @prismicio/next, even when logged out of Prismic. (It is still bounded by the limitations of our cookie-based preview system, so it won’t work in e.g. Safari by default.)

Can everyone share with me the version of the Next.js your using in your projects.

1 Like

@Phil As explained in my first post, I'm on next.js v11 but I can't use @prismicio/next or @prismicio/client v6 because the website is hosted on Amplify.

There needs to be way to have sharable previews even if not using @prismicio/next, right?

Hi Kris,

Without using @primsic/next creating shareable becomes very difficult given the static nature of Next.js deployments, your app needs to be able to allow the Prismic toolbar to search for Prismic cookies in the users' browser to activate Next.js' preview system.

I'll ask @angeloashmore how they implemented this in the package and how you might recreate it in your older project (I feel it might be easier to upgrade).

I'll get back to you with more info as soon as I can.

Thanks.

@Phil Thanks for the reply! Does that mean that before the introduction of @prismic/next, sharable previews didn't worked? I think the only time sharable previews work are for my Gatsby website, but don't think it has ever worked for any of my other websites...

That’s correct; sharable previews and exiting previews did not work for statically deployed Next.js projects without custom workarounds.

@prismicio/next standardizes and simplifies Next.js-specific preview implementation by using relatively new Prismic Toolbar APIs. The new Prismic Toolbar APIs were developed specifically to address shortcomings in preview support with statically generated sites.

The Prismic Toolbar should always load the latest version on your site and is unrelated to the version of @prismicio/client. The latest version includes new events that apps can hook into, including when a preview is updated and exited. It does not, however, include any special hooks or APIs to handle shared previews.

The following component is a modified version of from @prismicio/next. It can be copied into any Next.js project manually. It does not rely on @prismicio/client, but it does use the latest version of @prismicio/react. If the project does not use @prismicio/react, the component can be removed and replaced by a Next.js (see docs) to load the Prismic toolbar manually.

The original version can be seen here: prismic-next/PrismicPreview.tsx at 80e876f9e0a850761d725bc587e34a16f51db320 · prismicio/prismic-next · GitHub

import { useEffect } from "react";
import { PrismicToolbar } from "@prismicio/react";
import { useRouter } from "next/router";

/**
 * Reads and normalizes a cookie value. Used within `getPrismicPreviewCookie()`.
 *
 * @param value - Cookie Value to read.
 *
 * @returns Normalized value of the cookie.
 */
const readValue = (value: string): string => {
	return value.replace(/%3B/g, ";");
};

/**
 * Returns the value of a cookie from a given cookie store.
 *
 * @param cookieJar - The stringified cookie store from which to read the cookie.
 *
 * @returns The value of the cookie, if it exists.
 */
export const getPrismicPreviewCookie = (
	cookieJar: string,
): string | undefined => {
	const cookies = cookieJar.split("; ");

	let value: string | undefined;

	for (const cookie of cookies) {
		const parts = cookie.split("=");
		const name = readValue(parts[0]).replace(/%3D/g, "=");

		if (name === "io.prismic.preview") {
			value = readValue(parts.slice(1).join("="));
			continue;
		}
	}

	return value;
};

/**
 * Extracts preview reference repo name from stringified Prismic preview cookie
 *
 * @param previewCookie - The Prismic preview cookie.
 *
 * @returns The repository name for the Prismic preview cookie. If the cookie
 *   represents an inactive preview session, `undefined` will be returned.
 */
export const getPreviewCookieRepositoryName = (
	previewCookie: string,
): string | undefined => {
	return (decodeURIComponent(previewCookie).match(/"(.+).prismic.io"/) ||
		[])[1];
};

/**
 * Props for `<PrismicPreview>`.
 */
export type PrismicPreviewProps = {
	/**
	 * The name of your Prismic repository. A Prismic Toolbar will be registered
	 * using this repository.
	 */
	repositoryName: string;

	/**
	 * The URL of your app's Prismic preview endpoint (default: `/api/preview`).
	 * This URL will be fetched on preview update events.
	 *
	 * **Note**: If your `next.config.js` file contains a `basePath`, it is
	 * automatically included.
	 */
	updatePreviewURL?: string;

	/**
	 * The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
	 * This URL will be fetched on preview exit events.
	 *
	 * **Note**: If your `next.config.js` file contains a `basePath`, it is
	 * automatically included.
	 */
	exitPreviewURL?: string;

	/**
	 * Children to render adjacent to the Prismic Toolbar. The Prismic Toolbar
	 * will be rendered last.
	 */
	children?: React.ReactNode;
};

/**
 * React component that sets up Prismic Previews using the Prismic Toolbar. When
 * the Prismic Toolbar send events to the browser, such as on preview updates
 * and exiting, this component will automatically update the Next.js preview
 * cookie and refresh the page.
 *
 * This component can be wrapped around your app or added anywhere in your app's
 * tree. It must be rendered on every page.
 */
export function PrismicPreview({
	repositoryName,
	children,
	updatePreviewURL = "/api/preview",
	exitPreviewURL = "/api/exit-preview",
}: PrismicPreviewProps): JSX.Element {
	const router = useRouter();

	const resolvedUpdatePreviewURL = router.basePath + updatePreviewURL;
	const resolvedExitPreviewURL = router.basePath + exitPreviewURL;

	useEffect(() => {
		/**
		 * Starts Preview Mode and refreshes the page's props.
		 */
		const startPreviewMode = async () => {
			// Start Next.js Preview Mode via the given preview API endpoint.
			const res = await globalThis.fetch(resolvedUpdatePreviewURL);

			if (res.ok) {
				globalThis.location.reload();
			} else {
				console.error(
					`[<PrismicPreview>] Failed to start or update Preview Mode using the "${resolvedUpdatePreviewURL}" API endpoint. Does it exist?`,
				);
			}
		};

		const handlePrismicPreviewUpdate = async (event: Event) => {
			// Prevent the toolbar from reloading the page.
			event.preventDefault();

			await startPreviewMode();
		};

		const handlePrismicPreviewEnd = async (event: Event) => {
			// Prevent the toolbar from reloading the page.
			event.preventDefault();

			// Exit Next.js Preview Mode via the given preview API endpoint.
			const res = await globalThis.fetch(resolvedExitPreviewURL);

			if (res.ok) {
				globalThis.location.reload();
			} else {
				console.error(
					`[<PrismicPreview>] Failed to exit Preview Mode using the "${resolvedExitPreviewURL}" API endpoint. Does it exist?`,
				);
			}
		};

		if (router.isPreview) {
			// Register Prismic Toolbar event handlers.
			window.addEventListener(
				"prismicPreviewUpdate",
				handlePrismicPreviewUpdate,
			);
			window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
		} else {
			const prismicPreviewCookie = getPrismicPreviewCookie(
				globalThis.document.cookie,
			);

			if (prismicPreviewCookie) {
				// If a Prismic preview cookie is present, but Next.js Preview
				// Mode is not active, we must activate Preview Mode manually.
				//
				// This will happen when a visitor accesses the page using a
				// Prismic preview share link.

				/**
				 * Determines if the current location is a descendant of the app's base path.
				 *
				 * This is used to prevent infinite refrehes; when
				 * `isDescendantOfBasePath` is `false`, `router.isPreview` is also `false`.
				 *
				 * If the app does not have a base path, this should always be `true`.
				 */
				const locationIsDescendantOfBasePath = window.location.href.startsWith(
					window.location.origin + router.basePath,
				);

				const prismicPreviewCookieRepositoryName =
					getPreviewCookieRepositoryName(prismicPreviewCookie);

				if (
					locationIsDescendantOfBasePath &&
					prismicPreviewCookieRepositoryName === repositoryName
				) {
					startPreviewMode();
				}
			}
		}

		// On cleanup, unregister Prismic Toolbar event handlers.
		return () => {
			window.removeEventListener(
				"prismicPreviewUpdate",
				handlePrismicPreviewUpdate,
			);
			window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
		};
	}, [
		repositoryName,
		resolvedExitPreviewURL,
		resolvedUpdatePreviewURL,
		router.isPreview,
		router.basePath,
	]);

	return (
		<>
			{children}
			<PrismicToolbar repositoryName={repositoryName} />
		</>
	);
}

This component should be added to _app.js like so: Previews with Next.js - Prismic

1 Like

@Phil: Can you clarify exactly what shareable preview functionality should be supported through @prismicio/next? I'm having a hard time following this and other posts on the topic, and the "Preview drafts" documentation makes no mention of shareable links.

Earlier in this post (direct link), you mentioned that "anonymous share links should work with Next.js when set up with @prismicio/next, even when logged out of Prismic." This is great! Does this also work for documents that have never been published, or is that limitation still outstanding?

1 Like

My understanding is that all preview functionality works with @prismicio/next. What version are you using?

We're using v0.1.3, but only in an experimental/secondary repo where there may be some other configuration issues going on. If the official word from Prismic is that @prismicio/next now supports anonymous share links, even when logged out of Prismic and for never-published drafts, I think that's all I need for now. If I misunderstood your prior message or there are important gotchas you want to call out, please LMK!

No that's my understanding, as long as you're on the latest version, everything should work. Let me know how it goes.

1 Like

Hey @Phil, I'm a software engineer that works alongside @dan.duett. I wanted to follow up on this because I haven't been able to get shareable links working correctly when passing them to someone who is not logged into Prismic. In fact, when that link is opened by someone else, the browser infinitely refreshes itself. It's not clear why this is happening and does not happen for signed-in users.

Here are the list of steps to reproduce for us:

  1. Create and save a preview draft of a document. It does not matter if the document has never been published before or if it is already published, the end state is the same.
  2. Open the preview using the preview button in the Prismic editor.
  3. When the pop-up in the bottom-left appears, click "Get a shareable link".
  4. Copy that link and open in a new browser session. That browser session should not have any Prismic related cookies. This should replicate the experience of a stakeholder that doesn't have a Prismic account.
  5. See that the preview fails to load correctly. Instead, there is an endless loop of the page refreshing.

If it's helpful, I can DM you a link to a screen recording of the issue or provide you other details if desired. I'd prefer not making these public though.

I believe we've followed the setup instructions correctly. I can also see that Prismic toolbar script is available on the 404 page, so I don't think the issue is there.

Any guidance would be greatly appreciated and I'm happy to provide more information if you think it's helpful.

Node.js: 16.18.0 for local development but hosted on Netlify.

"next": "^12.3.0",
"@prismicio/client": "^6.6.2",
"@prismicio/helpers": "^2.3.2",
"@prismicio/next": "^0.1.6",
"@prismicio/react": "^2.4.4",

2 Likes