feat: add prolific info and docs page (#2853)
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 12 KiB |
131
apps/docs/app/link-surveys/market-research-panel/page.mdx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import CopySurveyLink from "./copy-survey-link.webp";
|
||||
import CreateStudy from "./create-study.webp";
|
||||
import HiddenFields from "./hidden-fields.webp";
|
||||
import PreviewComplete from "./preview-complete.webp";
|
||||
import PreviewStudy from "./preview-study.webp";
|
||||
import AddRedirectUrl from "./redirect-url-formbricks.webp";
|
||||
import RedirectUrl from "./redirect-url.webp";
|
||||
import ScreeningOut from "./screening-out.webp";
|
||||
import UrlParameters from "./url-parameters.webp";
|
||||
|
||||
|
||||
export const metadata = {
|
||||
title: "Creating a Research Panel with Prolific",
|
||||
description:
|
||||
"Formbricks surveys can be integrated with Prolifics participant panel easily. This tutorial walks you through the steps on how to access a pool of over 200.000 participants for your research.",
|
||||
};
|
||||
|
||||
#### Research Panel
|
||||
|
||||
# Creating a Research Panel with Prolific
|
||||
|
||||
You need a lot of research participants that match your target audience fast?
|
||||
|
||||
Formbricks integrates well with Prolific. Prolific provides a pool of over 200.000 research participants you can choose from. Run market research with Formbricks within hours, not days.
|
||||
|
||||
<Note>
|
||||
Prolific is a paid service. You need to fund your account to access the pool of participants. The cost depends on the number of participants you want to reach and the demographics you're targeting. You can get an estimate of the cost with the [Prolific price calculator](https://www.prolific.com/calculator)
|
||||
</Note>
|
||||
|
||||
## Purpose
|
||||
|
||||
External research panels are useful when:
|
||||
|
||||
- You don't have access to enough people who match your target audience
|
||||
- You want to reach a specific demographic
|
||||
- You want to reach a large number of people quickly
|
||||
|
||||
## Steps to Follow
|
||||
|
||||
### Step 1: Add hidden fields to the Formbricks survey
|
||||
To be able to attribute a completed answer to a research participant, you need to add hidden fields to your Formbricks survey. To do so, edit your survey and scroll down to the Hidden Fields card.
|
||||
|
||||
Add three fields with the IDs `PROLIFIC_PID`, `STUDY_ID`, and `SESSION_ID`.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFields}
|
||||
alt="Hidden fields added"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 2: Create an account on Prolific
|
||||
Go to [Prolific](https://app.prolific.co/) and create an account.
|
||||
|
||||
### Step 3: Create a study on Prolific
|
||||
Once you're logged in to Prolific, create a new study.
|
||||
<MdxImage
|
||||
src={CreateStudy}
|
||||
alt="Create a study on Prolific"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
|
||||
### Step 4: Copy the Formbricks survey link to the Prolific study
|
||||
We connect the Formbricks survey with the Prolific study by copying the survey link from Formbricks and pasting it into the Prolific study:
|
||||
|
||||
<MdxImage
|
||||
src={CopySurveyLink}
|
||||
alt="Copy the survey link"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 5: Choose URL parameters for attribution
|
||||
To attribute responses to the correct participant, you need to add URL parameters to the Formbricks survey link. The parameters are `PROLIFIC_PID`, `STUDY_ID`, and `SESSION_ID`, exactly like the hidden fields you added.
|
||||
<MdxImage
|
||||
src={UrlParameters}
|
||||
alt="Adding URL parameters to the survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 6: Update the Formbricks Redirect URL
|
||||
To ensure that participants are redirected back to Prolific after completing the survey, add the redirect URL provided in the Prolific study setup (e.g. `https://app.prolific.co/submissions/complete?cc=I2PWSFRG`)
|
||||
|
||||
Copy from Prolific:
|
||||
<MdxImage
|
||||
src={RedirectUrl}
|
||||
alt="Copy redirect URL"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Set it up as Redirect URL in the Response Options in Formbricks:
|
||||
<MdxImage
|
||||
src={AddRedirectUrl}
|
||||
alt="Add redirect URL to Formbricks"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 7: Preview the study
|
||||
Preview the study using Prolific's [Preview-functionality](https://researcher-help.prolific.com/hc/en-gb/articles/360009222853-Previewing-your-study)
|
||||
|
||||
<MdxImage
|
||||
src={PreviewStudy}
|
||||
alt="Preview study"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Got to the success screen? Then you're ready to publish your study!
|
||||
<MdxImage
|
||||
src={PreviewComplete}
|
||||
alt="Preview complete"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 8: Publish the study
|
||||
After you've published the study, you'll get the first responses within a few hours.
|
||||
|
||||
<Note>
|
||||
Prolific is a paid service. You need to fund your account to publish your study.
|
||||
</Note>
|
||||
|
||||
### That's it! 🎉
|
||||
Once you've published the survey, you can sit back and watch the responses come in. Prolific will take care of the rest.
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 39 KiB |
@@ -84,6 +84,7 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Hidden Fields", href: "/link-surveys/hidden-fields" },
|
||||
{ title: "Start At Question", href: "/link-surveys/start-at-question" },
|
||||
{ title: "Embed Surveys Anywhere", href: "/link-surveys/embed-surveys" },
|
||||
{ title: "Market Research Panel", href: "/link-surveys/market-research-panel" },
|
||||
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" },
|
||||
{ title: "User Metadata", href: "/global/metadata" },
|
||||
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowLeftIcon, BellRing, BlocksIcon, Code2Icon, LinkIcon, MailIcon } from "lucide-react";
|
||||
import { BellRing, BlocksIcon, Code2Icon, LinkIcon, MailIcon, UsersRound } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Badge } from "@formbricks/ui/Badge";
|
||||
import { Dialog, DialogContent } from "@formbricks/ui/Dialog";
|
||||
import { ShareSurveyLink } from "@formbricks/ui/ShareSurveyLink";
|
||||
import { EmailTab } from "./shareEmbedTabs/EmailTab";
|
||||
import { LinkTab } from "./shareEmbedTabs/LinkTab";
|
||||
import { WebpageTab } from "./shareEmbedTabs/WebpageTab";
|
||||
import { EmbedView } from "./shareEmbedModal/EmbedView";
|
||||
import { PanelInfoView } from "./shareEmbedModal/PanelInfoView";
|
||||
|
||||
interface ShareEmbedSurveyProps {
|
||||
survey: TSurvey;
|
||||
@@ -21,6 +19,7 @@ interface ShareEmbedSurveyProps {
|
||||
webAppUrl: string;
|
||||
user: TUser;
|
||||
}
|
||||
|
||||
export const ShareEmbedSurvey = ({ survey, open, setOpen, webAppUrl, user }: ShareEmbedSurveyProps) => {
|
||||
const router = useRouter();
|
||||
const environmentId = survey.environmentId;
|
||||
@@ -34,26 +33,26 @@ export const ShareEmbedSurvey = ({ survey, open, setOpen, webAppUrl, user }: Sha
|
||||
];
|
||||
|
||||
const [activeId, setActiveId] = useState(tabs[0].id);
|
||||
const [showInitialPage, setShowInitialPage] = useState(true);
|
||||
const [showView, setShowView] = useState("start");
|
||||
const [surveyUrl, setSurveyUrl] = useState("");
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setActiveId(tabs[0].id);
|
||||
setOpen(open);
|
||||
setShowInitialPage(open); // Reset to initial page when modal opens
|
||||
setShowView(open ? "start" : ""); // Reset to initial page when modal opens or closes
|
||||
|
||||
// fetch latest responses
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const handleInitialPageButton = () => {
|
||||
setShowInitialPage(!showInitialPage);
|
||||
setShowView("start");
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="w-full max-w-xl bg-white p-0 md:max-w-3xl lg:h-[700px] lg:max-w-5xl">
|
||||
{showInitialPage ? (
|
||||
{showView === "start" ? (
|
||||
<div className="h-full max-w-full overflow-hidden">
|
||||
<div className="flex h-[200px] w-full flex-col items-center justify-center space-y-6 p-8 text-center lg:h-2/5">
|
||||
<p className="pt-2 text-xl font-semibold text-slate-800">Your survey is public 🎉</p>
|
||||
@@ -66,10 +65,10 @@ export const ShareEmbedSurvey = ({ survey, open, setOpen, webAppUrl, user }: Sha
|
||||
</div>
|
||||
<div className="flex h-[300px] flex-col items-center justify-center gap-8 rounded-b-lg bg-slate-50 px-8 lg:h-3/5">
|
||||
<p className="-mt-8 text-sm text-slate-500">What's next?</p>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div className="grid grid-cols-4 gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleInitialPageButton}
|
||||
onClick={() => setShowView("embed")}
|
||||
className="flex flex-col items-center gap-3 rounded-lg border border-slate-100 bg-white p-4 text-sm text-slate-500 hover:border-slate-200 md:p-8">
|
||||
<Code2Icon className="h-6 w-6 text-slate-700" />
|
||||
Embed survey
|
||||
@@ -86,76 +85,32 @@ export const ShareEmbedSurvey = ({ survey, open, setOpen, webAppUrl, user }: Sha
|
||||
<BlocksIcon className="h-6 w-6 text-slate-700" />
|
||||
Setup integrations
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowView("panel")}
|
||||
className="relative flex flex-col items-center gap-3 rounded-lg border border-slate-100 bg-white p-4 text-sm text-slate-500 hover:border-slate-200 md:p-8">
|
||||
<UsersRound className="h-6 w-6 text-slate-700" />
|
||||
Send to panel
|
||||
<Badge size="tiny" type="success" text="New" className="absolute right-3 top-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full overflow-hidden">
|
||||
<div className="border-b border-slate-200 py-2">
|
||||
<Button
|
||||
variant="minimal"
|
||||
className="focus:ring-0"
|
||||
onClick={handleInitialPageButton}
|
||||
StartIcon={ArrowLeftIcon}>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid h-full grid-cols-4">
|
||||
<div className="col-span-1 hidden flex-col gap-3 border-r border-slate-200 p-4 lg:flex">
|
||||
{tabs.map((tab) => (
|
||||
<Button
|
||||
StartIcon={tab.icon}
|
||||
startIconClassName="h-4 w-4"
|
||||
variant="minimal"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveId(tab.id)}
|
||||
className={cn(
|
||||
"rounded-md border px-4 py-2 text-slate-600",
|
||||
// "focus:ring-0 focus:ring-offset-0", // enable these classes to remove the focus rings on buttons
|
||||
tab.id === activeId
|
||||
? "border-slate-200 bg-slate-100 font-semibold text-slate-900"
|
||||
: "border-transparent text-slate-500 hover:text-slate-700"
|
||||
)}
|
||||
aria-current={tab.id === activeId ? "page" : undefined}>
|
||||
{tab.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="col-span-4 h-full overflow-y-auto bg-slate-50 px-4 py-6 lg:col-span-3 lg:p-6">
|
||||
<div>
|
||||
{activeId === "email" ? (
|
||||
<EmailTab surveyId={survey.id} email={email} />
|
||||
) : activeId === "webpage" ? (
|
||||
<WebpageTab surveyUrl={surveyUrl} />
|
||||
) : activeId === "link" ? (
|
||||
<LinkTab
|
||||
survey={survey}
|
||||
webAppUrl={webAppUrl}
|
||||
surveyUrl={surveyUrl}
|
||||
setSurveyUrl={setSurveyUrl}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-2 rounded-md p-3 text-center lg:hidden">
|
||||
{tabs.slice(0, 2).map((tab) => (
|
||||
<Button
|
||||
variant="minimal"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveId(tab.id)}
|
||||
className={cn(
|
||||
"rounded-md px-4 py-2",
|
||||
tab.id === activeId
|
||||
? "bg-white text-slate-900 shadow-sm"
|
||||
: "border-transparent text-slate-700 hover:text-slate-900"
|
||||
)}>
|
||||
{tab.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
) : showView === "embed" ? (
|
||||
<EmbedView
|
||||
handleInitialPageButton={handleInitialPageButton}
|
||||
tabs={tabs}
|
||||
activeId={activeId}
|
||||
setActiveId={setActiveId}
|
||||
survey={survey}
|
||||
email={email}
|
||||
surveyUrl={surveyUrl}
|
||||
setSurveyUrl={setSurveyUrl}
|
||||
webAppUrl={webAppUrl}
|
||||
/>
|
||||
) : showView === "panel" ? (
|
||||
<PanelInfoView handleInitialPageButton={handleInitialPageButton} />
|
||||
) : null}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowLeftIcon } from "lucide-react";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { EmailTab } from "./EmailTab";
|
||||
import { LinkTab } from "./LinkTab";
|
||||
import { WebpageTab } from "./WebpageTab";
|
||||
|
||||
interface EmbedViewProps {
|
||||
handleInitialPageButton: () => void;
|
||||
tabs: Array<{ id: string; label: string; icon: any }>;
|
||||
activeId: string;
|
||||
setActiveId: React.Dispatch<React.SetStateAction<string>>;
|
||||
survey: any;
|
||||
email: string;
|
||||
surveyUrl: string;
|
||||
setSurveyUrl: React.Dispatch<React.SetStateAction<string>>;
|
||||
webAppUrl: string;
|
||||
}
|
||||
|
||||
export const EmbedView = ({
|
||||
handleInitialPageButton,
|
||||
tabs,
|
||||
activeId,
|
||||
setActiveId,
|
||||
survey,
|
||||
email,
|
||||
surveyUrl,
|
||||
setSurveyUrl,
|
||||
webAppUrl,
|
||||
}: EmbedViewProps) => {
|
||||
return (
|
||||
<div className="h-full overflow-hidden">
|
||||
<div className="border-b border-slate-200 py-2">
|
||||
<Button
|
||||
variant="minimal"
|
||||
className="focus:ring-0"
|
||||
onClick={handleInitialPageButton}
|
||||
StartIcon={ArrowLeftIcon}>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid h-full grid-cols-4">
|
||||
<div className="col-span-1 hidden flex-col gap-3 border-r border-slate-200 p-4 lg:flex">
|
||||
{tabs.map((tab) => (
|
||||
<Button
|
||||
StartIcon={tab.icon}
|
||||
startIconClassName="h-4 w-4"
|
||||
variant="minimal"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveId(tab.id)}
|
||||
className={cn(
|
||||
"rounded-md border px-4 py-2 text-slate-600",
|
||||
// "focus:ring-0 focus:ring-offset-0", // enable these classes to remove the focus rings on buttons
|
||||
tab.id === activeId
|
||||
? "border-slate-200 bg-slate-100 font-semibold text-slate-900"
|
||||
: "border-transparent text-slate-500 hover:text-slate-700"
|
||||
)}
|
||||
aria-current={tab.id === activeId ? "page" : undefined}>
|
||||
{tab.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="col-span-4 h-full overflow-y-auto bg-slate-50 px-4 py-6 lg:col-span-3 lg:p-6">
|
||||
<div>
|
||||
{activeId === "email" ? (
|
||||
<EmailTab surveyId={survey.id} email={email} />
|
||||
) : activeId === "webpage" ? (
|
||||
<WebpageTab surveyUrl={surveyUrl} />
|
||||
) : activeId === "link" ? (
|
||||
<LinkTab
|
||||
survey={survey}
|
||||
webAppUrl={webAppUrl}
|
||||
surveyUrl={surveyUrl}
|
||||
setSurveyUrl={setSurveyUrl}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-2 rounded-md p-3 text-center lg:hidden">
|
||||
{tabs.slice(0, 2).map((tab) => (
|
||||
<Button
|
||||
variant="minimal"
|
||||
key={tab.id}
|
||||
onClick={() => setActiveId(tab.id)}
|
||||
className={cn(
|
||||
"rounded-md px-4 py-2",
|
||||
tab.id === activeId
|
||||
? "bg-white text-slate-900 shadow-sm"
|
||||
: "border-transparent text-slate-700 hover:text-slate-900"
|
||||
)}>
|
||||
{tab.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
"use client";
|
||||
|
||||
import ProlificLogo from "@/images/prolific-logo.webp";
|
||||
import ProlificUI from "@/images/prolific-screenshot.webp";
|
||||
import { ArrowLeftIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
|
||||
interface PanelInfoViewProps {
|
||||
handleInitialPageButton: () => void;
|
||||
}
|
||||
|
||||
export const PanelInfoView = ({ handleInitialPageButton }: PanelInfoViewProps) => {
|
||||
return (
|
||||
<div className="h-full overflow-hidden text-slate-900">
|
||||
<div className="border-b border-slate-200 py-2">
|
||||
<Button
|
||||
variant="minimal"
|
||||
className="focus:ring-0"
|
||||
onClick={handleInitialPageButton}
|
||||
StartIcon={ArrowLeftIcon}>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid h-full grid-cols-2">
|
||||
<div className="flex flex-col gap-y-6 border-r border-slate-200 p-8">
|
||||
<Image src={ProlificUI} alt="Prolific panel selection UI" className="rounded-lg shadow-lg" />
|
||||
<div>
|
||||
<p className="text-md font-semibold">What is a panel?</p>
|
||||
<p className="text-slate-600">
|
||||
A panel is a group of participants selected based on characteristics such as age, profession,
|
||||
gender, etc.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">When do I need it?</p>
|
||||
<p className="text-slate-600">
|
||||
If you don’t have access to enough people who match your target audience, it makes sense to pay
|
||||
for access to a panel.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">What is Prolific?</p>
|
||||
<p className="text-slate-600">
|
||||
We’re partnering with Prolific to offer you access to a pool of 200.000 participant to do
|
||||
research with.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex flex-col gap-y-6 bg-slate-50 p-8">
|
||||
<Image
|
||||
src={ProlificLogo}
|
||||
alt="Prolific panel selection UI"
|
||||
className="absolute right-8 top-8 w-32"
|
||||
/>
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">How to create a panel</h3>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">Step 1: Create an account with Prolific</p>
|
||||
<p className="text-slate-600">
|
||||
We partner with Prolific to give you access to a pool of over 200.000 vetted participants.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">Step 2: Create a study</p>
|
||||
<p className="text-slate-600">
|
||||
At Prolific, you create a new study where you can pick your preferred audience based on hundreds
|
||||
of characteristics.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">Step 3: Connect your survey</p>
|
||||
<p className="text-slate-600">
|
||||
Set up hidden fields in your Formbricks survey to track which participant provided which answer.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-md font-semibold">Step 4: Launch your study</p>
|
||||
<p className="text-slate-600">
|
||||
Once everything is setup, you can launch your study. Within a few hours you’ll receive the first
|
||||
responses.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="justify-center"
|
||||
href="https://formbricks.com/docs/link-surveys/market-research-panel"
|
||||
target="_blank">
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
BIN
apps/web/images/prolific-logo.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
apps/web/images/prolific-screenshot.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |