> ## Documentation Index
> Fetch the complete documentation index at: https://beta-docs.replo.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Sell Something You Already Have

> Bring in the products you already sell and let Replo build the pages that sell them.

export const TryPromptButton = ({prompt, imageSrc, imageAlt = "Template preview", imageStyles = {}, buttonCta = "Build in Replo"}) => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const API_BASE = "https://api.replo.app";
  const APP_URL = "https://dashboard.replo.app";
  const LoaderIcon = <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    animation: "spin 1s linear infinite"
  }}>
      <path d="M21 12a9 9 0 1 1-6.219-8.56" />
    </svg>;
  const ChevronIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="m9 18 6-6-6-6" />
    </svg>;
  async function postJSON(url, body, headers = {}, timeoutMs = 120000) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body: JSON.stringify(body ?? ({})),
        signal: controller.signal
      });
      const responseText = await response.text();
      if (!response.ok) throw new Error(`API Error: ${response.status}`);
      return responseText ? JSON.parse(responseText) : {};
    } finally {
      clearTimeout(timeoutId);
    }
  }
  async function handleTryPrompt(event) {
    event.preventDefault();
    event.stopPropagation();
    setIsLoading(true);
    setError(null);
    try {
      const body = {
        prompt,
        file: null
      };
      const {seed} = await postJSON(`${API_BASE}/api/v1/marketing/issue-marketing-site-jwt`, body);
      if (!seed) throw new Error("No seed returned from API");
      const url = new URL(APP_URL);
      url.searchParams.set("type", "agent");
      url.hash = `seed=${encodeURIComponent(seed)}`;
      window.open(url.toString(), "_blank");
      setIsLoading(false);
    } catch (caughtError) {
      console.error("Failed to generate prompt:", caughtError);
      const message = caughtError instanceof Error ? caughtError.message : null;
      setError(message ?? "Something went wrong. Please try again.");
      setIsLoading(false);
    }
  }
  return <div style={{
    position: "relative",
    display: "inline-block",
    width: "100%"
  }}>
      {}
      {imageSrc && <img src={imageSrc} alt={imageAlt} style={{
    width: "100%",
    height: "auto",
    display: "block",
    borderRadius: "8px",
    opacity: 0.8,
    ...imageStyles
  }} />}

      {}
      <div style={imageSrc ? {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 10
  } : {
    display: "flex",
    justifyContent: "flex-start",
    margin: "1.25rem 0"
  }}>
        <button type="button" className="try-replo-btn" onClick={handleTryPrompt} disabled={isLoading} style={{
    backgroundColor: "#274AE2",
    color: "#ffffff",
    padding: "0.5rem 1.1rem",
    fontSize: "0.875rem",
    fontWeight: 600,
    fontFamily: "inherit",
    border: "none",
    borderRadius: "9999px",
    cursor: isLoading ? "not-allowed" : "pointer",
    lineHeight: 1.4,
    whiteSpace: "nowrap",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    WebkitFontSmoothing: "antialiased",
    boxSizing: "border-box",
    opacity: isLoading ? 0.7 : 1,
    boxShadow: "0 1px 2px rgba(15, 23, 42, 0.08)",
    transition: "background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease"
  }}>
          <span style={{
    visibility: isLoading ? "hidden" : "visible",
    display: "inline-flex",
    alignItems: "center",
    gap: "0.375rem"
  }}>
            {buttonCta}
            {ChevronIcon}
          </span>
          {isLoading && <span style={{
    position: "absolute",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
              {LoaderIcon}
            </span>}
        </button>
      </div>

      {}
      <style>
        {`
          @keyframes spin {
            from {
              transform: rotate(0deg);
            }
            to {
              transform: rotate(360deg);
            }
          }
          .try-replo-btn:hover:not(:disabled) {
            background-color: #1f3ec0 !important;
            box-shadow: 0 4px 12px rgba(39, 74, 226, 0.35);
            transform: translateY(-1px);
          }
          .try-replo-btn:active:not(:disabled) {
            transform: translateY(0);
            box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
          }
          .try-replo-btn:focus-visible {
            outline: 2px solid #274AE2;
            outline-offset: 2px;
          }
        `}
      </style>

      {}
      {error && <div style={{
    marginTop: "12px",
    padding: "12px 16px",
    backgroundColor: "#fee",
    border: "1px solid #fcc",
    borderRadius: "6px",
    color: "#c33",
    fontSize: "14px",
    textAlign: "center"
  }} role="alert">
          {error}
        </div>}
    </div>;
};

export const Screenshot = ({src, altText, width, shadow = true}) => {
  const generateAltText = imageSrc => {
    if (!imageSrc) return "Screenshot";
    const filename = imageSrc.split("/").pop() ?? "";
    const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
    const readable = nameWithoutExt.replace(/[-_]/g, " ").replace(/\b\w/g, char => char.toUpperCase());
    return readable === "" ? "Screenshot" : readable;
  };
  const finalAltText = altText ?? generateAltText(src);
  const imageWidth = width ? `${width}px` : "100%";
  return <div style={{
    position: "relative",
    width: "100%",
    borderRadius: "12px",
    overflow: "hidden",
    boxSizing: "border-box",
    display: "flex",
    justifyContent: "center"
  }}>
      {}
      <svg style={{
    position: "absolute",
    top: 0,
    left: 0,
    width: "100%",
    height: "100%",
    zIndex: 0,
    pointerEvents: "none"
  }} viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice">
        <g clipPath="url(#clip0_5067_2569)">
          <rect width="1920" height="1080" fill="black" />
          <g opacity="0.9" filter="url(#filter0_fn_5067_2569)">
            <mask id="mask0_5067_2569" style={{
    maskType: "alpha"
  }} maskUnits="userSpaceOnUse" x="539" y="-367" width="2018" height="1261">
              <rect x="539" y="-367" width="2017.6" height="1261" fill="#C4C4C4" />
            </mask>
            <g mask="url(#mask0_5067_2569)">
              <g filter="url(#filter1_f_5067_2569)">
                <path d="M880.949 82.6474L1798.19 -385.441L2215.11 -385.441L2725.35 -260.618L936.539 437.057L880.949 82.6474Z" fill="url(#paint0_linear_5067_2569)" />
              </g>
              <g filter="url(#filter2_f_5067_2569)">
                <ellipse cx="462.152" cy="150.719" rx="462.152" ry="150.719" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1250.96 112.228)" fill="#FEBC2E" />
              </g>
              <g filter="url(#filter3_f_5067_2569)">
                <path d="M1687.1 56.3942C2102.4 -149.497 2274.54 -159.301 2672.61 -80.8668L2803.87 183.851L884.491 784.367C849.346 777.831 951.195 612.791 1228.77 362.78C1281.1 315.653 1271.81 262.285 1687.1 56.3942Z" fill="url(#paint1_linear_5067_2569)" />
              </g>
              <g opacity="0.7" filter="url(#filter4_f_5067_2569)">
                <path d="M1975.09 -76.9728C2367.51 -238.299 2270.38 -191.657 2637.67 -120.329L2758.78 120.402L1001.73 662.047C969.304 656.104 932.244 530.091 1043.42 349.988C1182.4 124.86 1518.29 110.824 1975.09 -76.9728Z" fill="#B7FEAE" fillOpacity="0.5" />
              </g>
              <g filter="url(#filter5_f_5067_2569)">
                <path d="M2052.63 99.5535C2383.11 16.7587 2366.44 -59.7112 2665.61 -7.17013L2707.81 170.156L1276.64 569.14C1250.23 564.762 1220.04 471.939 1310.6 339.273C1423.8 173.44 1803.59 161.946 2052.63 99.5535Z" fill="#EF196E" />
              </g>
              <g opacity="0.4" filter="url(#filter6_f_5067_2569)">
                <ellipse cx="462.152" cy="218.806" rx="462.152" ry="218.806" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1152.46 417.938)" fill="#FFEB80" />
              </g>
              <g filter="url(#filter7_f_5067_2569)">
                <ellipse cx="462.152" cy="150.719" rx="462.152" ry="150.719" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1913.18 237.904)" fill="#B7FEAE" />
              </g>
              <g filter="url(#filter8_f_5067_2569)">
                <g opacity="0.4" filter="url(#filter9_f_5067_2569)">
                  <path d="M1551.1 493.269L2619.23 -0.477507L3125.23 -71.2418L3756.49 -67.6927L1652.68 739.798L1551.1 493.269Z" fill="url(#paint2_linear_5067_2569)" />
                </g>
              </g>
              <g filter="url(#filter10_f_5067_2569)">
                <g opacity="0.4" filter="url(#filter11_f_5067_2569)">
                  <path d="M1696.12 652.03L2820.04 310.947L3330.91 310.947L3956.12 401.903L1764.24 910.278L1696.12 652.03Z" fill="url(#paint3_linear_5067_2569)" />
                </g>
                <g opacity="0.4" filter="url(#filter12_f_5067_2569)">
                  <path d="M1628.55 727.676L2843.38 257.743L3271.53 195.271L3903.03 210.271L1788.72 978.91L1628.55 727.676Z" fill="url(#paint4_linear_5067_2569)" />
                </g>
              </g>
            </g>
          </g>
        </g>
        <defs>
          <filter id="filter0_fn_5067_2569" x="637.809" y="-607" width="2158.79" height="1741" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="120" result="effect1_foregroundBlur_5067_2569" />
            <feTurbulence type="fractalNoise" baseFrequency="1 1" stitchTiles="stitch" numOctaves="3" result="noise" seed="7978" />
            <feColorMatrix in="noise" type="luminanceToAlpha" result="alphaNoise" />
            <feComponentTransfer in="alphaNoise" result="coloredNoise1">
              <feFuncA type="discrete" tableValues="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " />
            </feComponentTransfer>
            <feComposite operator="in" in2="effect1_foregroundBlur_5067_2569" in="coloredNoise1" result="noise1Clipped" />
            <feFlood floodColor="rgba(0, 0, 0, 0.25)" result="color1Flood" />
            <feComposite operator="in" in2="noise1Clipped" in="color1Flood" result="color1" />
            <feMerge result="effect2_noise_5067_2569">
              <feMergeNode in="effect1_foregroundBlur_5067_2569" />
              <feMergeNode in="color1" />
            </feMerge>
          </filter>
          <filter id="filter1_f_5067_2569" x="878.4" y="-387.991" width="1849.5" height="827.597" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.27461" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter2_f_5067_2569" x="1129.77" y="-334.846" width="1187.61" height="805.41" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="84.0203" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter3_f_5067_2569" x="855.856" y="-148.194" width="1969.97" height="954.514" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="10.9761" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter4_f_5067_2569" x="958.113" y="-196.498" width="1811.26" height="869.143" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.29875" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter5_f_5067_2569" x="1149.75" y="-124.443" width="1658.06" height="793.583" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="50" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter6_f_5067_2569" x="1098.27" y="39.191" width="1098.61" height="797.277" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="60.1484" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter7_f_5067_2569" x="1886.85" y="-114.306" width="997.881" height="615.684" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="36.5888" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter8_f_5067_2569" x="1540.3" y="-82.0399" width="2226.99" height="832.636" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.39908" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter9_f_5067_2569" x="1547.97" y="-74.3651" width="2211.64" height="817.287" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.56172" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter10_f_5067_2569" x="1598.84" y="165.553" width="2387" height="843.074" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="14.8586" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter11_f_5067_2569" x="1693" y="307.824" width="2266.24" height="605.577" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.56172" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter12_f_5067_2569" x="1617.84" y="184.562" width="2295.9" height="805.057" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.35445" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <linearGradient id="paint0_linear_5067_2569" x1="1803.15" y1="-385.441" x2="1040.5" y2="259.543" gradientUnits="userSpaceOnUse">
            <stop stopColor="#FF7D54" />
            <stop offset="1" stopColor="white" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint1_linear_5067_2569" x1="2283.14" y1="-17.1385" x2="1351.98" y2="310.625" gradientUnits="userSpaceOnUse">
            <stop stopColor="#B7FEAE" />
            <stop offset="0.65537" stopColor="#EF196E" />
            <stop offset="1" stopColor="#274AE2" />
          </linearGradient>
          <linearGradient id="paint2_linear_5067_2569" x1="2625.25" y1="-1.32004" x2="2201.56" y2="820.649" gradientUnits="userSpaceOnUse">
            <stop stopColor="#3A4CF0" />
            <stop offset="1" stopColor="#F5FAD9" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint3_linear_5067_2569" x1="2826.12" y1="310.947" x2="2295.81" y2="1065.13" gradientUnits="userSpaceOnUse">
            <stop stopColor="#EF196E" />
            <stop offset="1" stopColor="white" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint4_linear_5067_2569" x1="2452.05" y1="509.031" x2="2135.78" y2="1074.58" gradientUnits="userSpaceOnUse">
            <stop offset="0.166667" stopColor="#EF196E" />
            <stop offset="0.541667" stopColor="#FFEB80" stopOpacity="0.25" />
            <stop offset="1" stopColor="#274AE2" stopOpacity="0" />
          </linearGradient>
          <clipPath id="clip0_5067_2569">
            <rect width="1920" height="1080" fill="white" />
          </clipPath>
        </defs>
      </svg>

      {}
      <div style={{
    position: "relative",
    zIndex: 1,
    padding: "clamp(24px, 4vw, 48px)",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "100%"
  }}>
        <img src={src} alt={finalAltText} style={{
    width: imageWidth,
    maxWidth: "100%",
    height: "auto",
    display: "block",
    borderRadius: "8px",
    boxShadow: shadow ? "0 20px 60px rgba(0, 0, 0, 0.3)" : "none"
  }} />
      </div>
    </div>;
};

You already sell something, whether it is on Shopify, at markets, or over DMs, and you want pages that sell it better. Replo pulls in your products, builds product pages and funnels around them, and publishes the result on your own domain.

The strongest version of this today is with Shopify. Connect your store, and your real products, with their real prices, variants, and images, become things Replo can build with directly.

## Why mention products instead of describing them

A mentioned product is live data, not a description. Replo reads the title, price, variants, and images straight from your store, so the page it builds stays accurate, and you never retype a price into a paragraph.

## Build it

<Steps>
  <Step title="Connect your store">
    In [Integrations](/apps/integrations), connect Shopify. Replo can then see your products, collections, prices, and images.

    <Screenshot src="/images/cropped/integration-shopify-connect.png" altText="The Shopify integration page in Replo, showing a Project connection card with a Connect button" />
  </Step>

  <Step title="Point Replo at a product">
    Type `@` in the chat to mention a product or collection, and tell Replo what to build with it.

    <Screenshot src="/images/cropped/mention-menu.png" altText="The @ mention menu in chat showing a Products section alongside assets and integrations" width="340" />

    ```text theme={null}
    Build a landing page for @Lavender-Candle with a hero, three benefit
    sections, reviews, and a buy section.
    ```

    <TryPromptButton prompt="Build a landing page for a lavender soy candle with a hero, three benefit sections, reviews, and a buy section." />
  </Step>

  <Step title="Build the pages">
    Replo builds product pages, landing pages, and funnels using your real product data, so prices and variants are always right.

    <Screenshot src="/images/cropped/built-site-home.png" altText="A built homepage shown in the Website Builder, with the chat summarizing the brand and product content Replo pulled from an existing store" />
  </Step>

  <Step title="Publish">
    Publish to a Replo subdomain or [your own domain](/custom-domains). Buy buttons link your customers into your store's checkout.

    <Screenshot src="/images/cropped/publish-publishing.png" altText="The website builder publishing the site, with a popover showing the Replo subdomain the pages will go live at" />
  </Step>
</Steps>

## Related

<CardGroup cols={2}>
  <Card title="Integrations" icon="plug" href="/apps/integrations">Connect Shopify and your other tools.</Card>
  <Card title="Publishing" icon="globe" href="/publishing">Take your pages live.</Card>
</CardGroup>
