You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:Shopify生产店铺Web Pixel扩展激活失败(已试三种方案)

生产店铺中激活Shopify Web Pixel扩展遇到的问题

问题描述

我正尝试在Shopify生产店铺中激活Web Pixel扩展。该Web Pixel扩展已在Shopify Remix应用模板中配置,后端基于Express.js搭建。

已尝试方案

方案一:通过Shopify app dev GraphQL激活(仅测试店铺可用)

按照官方指引,通过Shopify app dev GraphQL在开发/测试店铺成功激活了该扩展。但生产店铺无法运行shopify app dev打开Shopify GraphQL控制台,因此该方法无法适用。

使用的GraphQL mutation:

mutation {
  # This mutation creates a web pixel, and sets the `accountID` declared in `shopify.extension.toml` to the value `123`.
  webPixelCreate(webPixel: { settings: "{\"accountID\":\"123\"}" }) {
    userErrors {
      code
      field
      message
    }
    webPixel {
      settings
      id
    }
  }
}

方案二:通过Shopify Remix应用的loader函数激活

尝试了社区指引中通过Shopify Remix应用的loader函数激活Pixel的方法,但未能成功。

对应Shopify Remix应用模板 > app/app._index.jsx代码:

export const loader = async ({ request }) => { // Authenticate with Shopify const { admin } = await authenticate.admin(request); 
const mutationResponse = await admin.graphql( #graphql
        mutation webPixelCreate($webPixel: WebPixelInput!) {
          webPixelCreate(webPixel: $webPixel) {
            userErrors {
              field
              message
            }
            webPixel {
              settings
              id
            }
          }
        }
      , { variables: { webPixel: { settings: { "accountID": 'Account_ID_45466_this_is_as_per_toml'
}, }, }, } ); 
if (!mutationResponse.ok) { console.error('Request failed', mutationResponse); return; } 
const data = await mutationResponse.json(); console.log(data); 
return mutationResponse; 
};

const loaderDataForWebPixel = useLoaderData();

方案三:Express.js端点实现OAuth重定向与令牌交换

在Express.js端点中实现OAuth重定向与令牌交换,对应routes/shopifyRouter.js文件:

import { shopify } from '../shopifyApi.js';
import { Router } from 'express';
import dotenv from 'dotenv';
import { shopify, RequestedTokenType } from '../shopifyApi.js'; 
import cookieParser from 'cookie-parser';
import axios from 'axios';

dotenv.config();


const router = Router();

// Middleware to set CSP headers for embedded apps
const setCSPHeaders = (req, res, next) => {
  const shop = req.query.shop;
  const shopDomain = shop ? `https://${shop}` : null;
  const shopifyAdminDomain = "https://admin.shopify.com";

  if (shopDomain) {
    res.setHeader("Content-Security-Policy", `frame-ancestors ${shopDomain} ${shopifyAdminDomain}`);
  } else {
    res.setHeader("Content-Security-Policy", `frame-ancestors ${shopifyAdminDomain}`);
  }
  next();
};


router.use((req, res, next) => {
  console.log(`Incoming request: ${req.method} ${req.url}`);
  next();
});


// Apply middleware
router.use(cookieParser());
router.use(setCSPHeaders);

// Route to handle the initial OAuth
router.get('/install', async (req, res) => {
  try {
    const shop = req.query.shop;

    if (!shop) {
      return res.status(400).json({ error: 'Missing "shop" query parameter' });
    }

    await shopify.auth.begin({
      shop,
      callbackPath: '/auth/callback',
      isOnline: false,
      rawRequest: req,
      rawResponse: res,
    });
  } catch (error) {
    console.error('Error during install:', error.message);
    console.error('Stack trace:', error.stack);
    res.status(500).json({ error: 'Error during install', message: error.message });
  }
});

// Route to handle the OAuth callback and activate web pixel
router.get('/auth/callback', async (req, res) => {
  try {
    const callbackResponse = await shopify.auth.callback({
      rawRequest: req,
      rawResponse: res,
    });
    const { session } = callbackResponse;
    const accessToken = session.accessToken;

    // Activate web pixel
    const graphqlUrl = `https://${session.shop}/admin/api/2023-07/graphql.json`;
    const graphqlHeaders = {
      'Content-Type': 'application/json',
      'X-Shopify-Access-Token': accessToken,
    };
    const graphqlMutation = {
      query: `
        mutation {
          webPixelCreate(webPixel: { settings: "{\\\"accountID\\\":\\\"88888888\\\"}" }) {
            userErrors {
              code
              field
              message
            }
            webPixel {
              settings
              id
            }
          }
        }
      `,
    };

    const graphqlResponse = await axios.post(graphqlUrl, graphqlMutation, { headers: graphqlHeaders });

    if (graphqlResponse.data.errors) {
      console.error('GraphQL errors:', graphqlResponse.data.errors);
      return res.status(500).json({ error: graphqlResponse.data.errors });
    }

    console.log('Web pixel activated:', graphqlResponse.data.data);
    res.json(graphqlResponse.data.data);
  } catch (error) {
    console.error('Error during OAuth callback:', error.message);
    console.error('Stack trace:', error.stack);
    res.status(500).json({ error: 'Error during OAuth callback', message: error.message });
  }
});

// Route get access token and activate web pixel
router.get('/auth', async (req, res) => {
  try {
    const shop = shopify.utils.sanitizeShop(req.query.shop, true);
    const headerSessionToken = getSessionTokenHeader(req);
    const searchParamSessionToken = getSessionTokenFromUrlParam(req);
    const sessionToken = headerSessionToken || searchParamSessionToken;

    

    if (!sessionToken) {
      return res.status(400).json({ error: 'Missing session token' });
    }

    const session = await shopify.auth.tokenExchange({
      sessionToken,
      shop,
      requestedTokenType: RequestedTokenType.OfflineAccessToken, // or RequestedTokenType.OnlineAccessToken
    });



    // Activate web pixel
    const accessToken = session.accessToken;
    console.log("🚀 ~ file: shopifyRouter.js:132 ~ router.get ~ accessToken:", accessToken);
    

    const graphqlUrl = `https://${shop}/admin/api/2023-07/graphql.json`;
    const graphqlHeaders = {
      'Content-Type': 'application/json',
      'X-Shopify-Access-Token': accessToken,
    };
    const graphqlMutation = {
      query: `
        mutation {
          webPixelCreate(webPixel: { settings: "{\\\"accountID\\\":\\\"88888888\\\"}" }) {
            userErrors {
              code
              field
              message
            }
            webPixel {
              settings
              id
            }
          }
        }
      `,
    };

    const graphqlResponse = await axios.post(graphqlUrl, graphqlMutation, { headers: graphqlHeaders });

    if (graphqlResponse.data.errors) {
      console.error('GraphQL errors:', graphqlResponse.data.errors);
      return res.status(500).json({ error: graphqlResponse.data.errors });
    }

    console.log('Web pixel activated:', graphqlResponse.data.data);
    res.json(graphqlResponse.data.data);
  } catch (error) {
    console.error('Error during token exchange:', error.message);
    console.error('Stack trace:', error.stack);
    res.status(500).json({ error: 'Error during token exchange', message: error.message });
  }
});

// Helper functions to get session token
function getSessionTokenHeader(request) {
  const authHeader = request.headers.authorization;
  if (authHeader && authHeader.startsWith('Bearer ')) {
    return authHeader.substring(7);
  }
  return null;
}

function getSessionTokenFromUrlParam(request) {
  return request.query.id_token || null;
}

export default router;

对应的shopifyApi.js文件代码:

import '@shopify/shopify-api/adapters/node'; 
import { shopifyApi, LATEST_API_VERSION, RequestedTokenType } from '@shopify/shopify-api';


import dotenv from 'dotenv';

dotenv.config();

const myAppsLogFunction = (severity, message) => {
  console.log(`[${severity}] ${message}`);
};

let shopify;

try {
  shopify = shopifyApi({
    apiKey: process.env.SHOPIFY_API_KEY,
    apiSecretKey: process.env.SHOPIFY_API_SECRET,
    scopes: ['read_products', 'write_products', 'read_customer_events', 'write_pixels'],
    hostName: process.env.SHOPIFY_APP_HOST,    
    hostScheme: 'https',
    apiVersion: LATEST_API_VERSION,    
    isEmbeddedApp: true,
    isCustomStoreApp: false,
    userAgentPrefix: 'Custom prefix',
    logger: {
      log: (severity, message) => {
        myAppsLogFunction(severity, message);
      },
      level: 'info',
      httpRequests: true,
      timestamps: true,
    },
    future: {
      unstable_newEmbeddedAuthStrategy: true,
    }
  });

  
  
} catch (error) {
  console.log('shopifyApi.js error', error);
}

export { shopify, RequestedTokenType };

方案三执行结果

  • express-url-endpoint/install返回错误:
{
"error": 
"Error during Oauth callback", 
"message": "Cannot complete Oauth process. Could not find an Oauth cookie for shop url: the-shop.myshopify.com"
}
  • express-url-endpoint/auth令牌交换返回错误:
{
    "error": "Error during token exchange",
    "message": "Request failed with status code 401"
}

内容的提问来源于stack exchange,提问作者kaizen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:47:04