文章目录
这篇教程不追求一次做出一个复杂 SaaS,而是先完成一个可以验证的真实项目:
Product Sync Manager:把 Shopify 商品同步到 Gadget,并在商品变化时实时更新。
完成后,你会得到一个能够:
- 安装到 Shopify 开发商店
- 显示在 Shopify Admin 中
- 通过 OAuth 完成商店授权
- 同步历史商品、变体和图片
- 接收商品创建、修改和删除 Webhook
- 在 Webhook 后执行自定义逻辑
- 使用 React 显示商品列表
- 部署到 Gadget Production
的基础 Shopify App。
说明:Gadget 的页面名称、模型名称和 Action 文件结构可能随模板和版本变化。下面涉及 Gadget 的菜单时,以项目实际显示为准,不要机械照抄固定路径。
一、先看懂应用是怎么工作的
这个项目的整体结构如下:
商家安装应用
↓
Shopify OAuth 授权
↓
Gadget 保存商店连接
↓
Gadget 调用 Shopify Admin API
↓
读取商品数据
↓
保存到 Gadget 数据库
↓
Shopify 发送商品 Webhook
↓
Gadget 更新数据库
↓
React 页面显示结果
每个部分负责不同工作:
| 部分 | 作用 |
|---|---|
| Shopify | 保存商店和商品数据 |
| Gadget | 提供后端、数据库、授权和部署能力 |
| Admin API | 让应用读取或修改 Shopify 后台数据 |
| PostgreSQL | 保存同步后的数据 |
| Webhook | Shopify 主动通知商品变化 |
| React | 显示应用界面 |
可以把它想象成一个机器人助手:
- Shopify 是商店
- Gadget 是机器人的身体
- Database 是机器人的记忆
- API 是机器人和商店沟通的窗口
- Webhook 是商店主动打来的电话
- React 是机器人展示给商家看的界面
二、开始前的准备
开始前准备:
- Shopify Partners 或 Shopify 开发者账号
- 一个 Shopify Development Store
- 一个 Gadget 账号
- 一个 Shopify App
- Chrome 浏览器
- 一个用于测试的开发商店
如果要测试正式安装,还需要一个可安装应用的正式 Shopify 商店。
开发阶段建议使用带测试数据的开发商店。测试数据可以帮助你快速得到:
- 商品
- 商品变体
- 商品图片
- 客户
- 订单
- 库存
不要一开始就直接连接真实商店。开发期间的错误、重复 Webhook 和测试商品可能会影响真实业务。
三、创建 Shopify 开发商店
登录 Shopify Partners 或 Shopify Dev Dashboard,进入开发商店管理页面。
当前后台可能显示为:
Stores → Add store
Create development store
Development stores
Add development store
创建时可以填写:
Store name: cart-transform-testing
Purpose: App development
Test data: Pre-populated test data
创建完成后,商店后台地址通常类似:
https://cart-transform-testing.myshopify.com/admin
记住这个 .myshopify.com 域名,后面安装应用和排查问题时会用到。
四、创建 Shopify App
Shopify 当前的应用管理以 Dev Dashboard 为中心。需要完整应用界面的项目,可以考虑使用 Shopify CLI;主要做数据同步、后台自动化或 API 集成时,也可以直接在 Dev Dashboard 配置应用。
不要把菜单路径写死成某一个版本。常见入口可能包括:
Apps → Create app
Create app manually
Build an app manually
开发应用可以命名为:
Product Sync Manager - Development
创建后记录:
Development Client ID
Development Client Secret
这两个值的作用不同:
- Client ID:应用的身份编号
- Client Secret:证明应用身份的秘密钥匙
Client Secret 只能放在服务端或安全的环境变量中,不能:
- 写入 React 前端
- 提交到 GitHub
- 放在公开截图中
- 复制到博客示例里
- 直接发给不需要它的人
Shopify 的应用配置还会涉及应用版本、App URL、API 权限和 Webhook API 版本。配置修改后,通常需要创建或发布新的应用版本。citation:Building apps
五、创建 Gadget 项目
登录 Gadget,创建一个新的 Shopify 应用项目。
项目名可以使用:
my-first-shopify-app
建议:
- 使用英文
- 使用小写字母
- 使用连字符
- 不要包含密码
- 不要把真实商家的敏感信息写进项目名
创建时选择类似以下选项:
Shopify App
Shopify Connection
Connect to Shopify
具体名称以当前 Gadget 页面为准。
Gadget 通常可以帮助项目准备:
- Node.js 后端
- React 前端
- PostgreSQL 数据库
- Shopify OAuth 连接
- Session Token 验证
- Shopify API 客户端
- Webhook 接收能力
- Development 和 Production 环境
但不要默认“创建了 Shopify Connection,就代表所有同步和 Webhook 都已经完成”。创建后仍然需要检查连接配置、模型、权限和 Webhook 设置。
六、配置 Shopify Connection
在 Gadget 项目中找到 Shopify Connection,常见位置可能是:
Connections → Shopify
或者:
Settings → Connections → Shopify
将 Shopify 中的开发环境凭据填入 Gadget:
Client ID
Client Secret
保存前检查:
- Client ID 没有多余空格
- Client Secret 没有多余空格
- 两个字段没有填反
- Development 凭据没有填到 Production
- 凭据属于当前 Shopify App
如果 Gadget 提供测试连接按钮,可以保存后执行连接测试。
七、只申请当前需要的权限
本教程第一版只同步商品,因此建议先申请:
read_products
如果应用还需要修改商品,再考虑:
write_products
其他常见权限包括:
| 功能 | 可能需要的权限 |
|---|---|
| 查看商品 | read_products |
| 修改商品 | write_products |
| 查看订单 | read_orders |
| 查看客户 | read_customers |
| 查看库存 | read_inventory |
| 修改库存 | write_inventory |
不要为了方便一次申请全部权限。
权限越多:
- 商家越难理解应用需要什么
- 授权页面越复杂
- 数据保护要求可能越高
- 应用审核可能更复杂
- 后续权限调整更麻烦
如果已经安装应用后又新增 Scope,旧安装通常需要重新授权,才能获得新增权限。
八、配置 App URL 和 OAuth 回调地址
这是最容易出错的步骤。
Shopify 需要知道两个地址:
App URL
OAuth Callback URL
从 Gadget 的 Shopify Connection、安装说明或部署页面中复制实际地址,不要根据教程示例手动猜。
可能类似:
https://your-app.gadget.app
OAuth 回调地址可能类似:
https://your-app.gadget.app/api/connections/auth/shopify/callback
然后回到 Shopify App 配置中,填写:
App URL
Allowed redirection URL
如果 Gadget 显示多个回调地址,就按照 Gadget 的要求全部添加。
重点检查:
- 必须使用 HTTPS
- App URL 和回调 URL 不要填反
- 路径不能少
- 开发地址和生产地址不能混用
- 结尾斜杠保持一致
- 不要复制隐藏空格
- 当前 Client ID 必须属于当前环境
同时确认应用启用了:
Embedded App
Embed app in Shopify admin
九、安装应用到开发商店
回到 Shopify App 管理页面,找到测试或安装入口。名称可能是:
Select store
Test your app
Install app
Choose development store
选择:
cart-transform-testing
点击安装后,Shopify 会显示应用申请的权限。
确认权限后点击:
Install
整个过程大致是:
Shopify 发起 OAuth
↓
Gadget 验证授权请求
↓
商家同意权限
↓
Gadget 保存商店连接
↓
应用完成安装
↓
页面跳转到 Embedded App
安装后先不要急着做同步,先确认:
- 应用能从 Shopify Admin 打开
- 没有无限跳转
- 没有拒绝访问错误
- 刷新页面后仍然能打开
- Gadget 中出现了当前商店记录
十、区分三种重要凭证
开发时经常把这些概念混在一起。
| 凭证 | 用途 | 保存位置 |
|---|---|---|
| Client ID | 识别应用是谁 | 应用配置 |
| Client Secret | 证明应用身份 | 服务端密钥 |
| Session Token | 验证嵌入式页面请求身份 | 前端请求和后端验证流程 |
| Admin API Access Token | 让服务器代表商店调用 Admin API | 只能保存在服务端 |
正确的数据流应该是:
React 页面
↓ Session Token
Gadget 后端确认当前商店
↓ Access Token
Shopify Admin API
不要这样做:
React 页面
↓ Access Token
Shopify Admin API
Access Token 一旦放到浏览器中,就可能被用户或恶意脚本看到。
十一、执行第一次历史同步
Webhook 只能通知安装之后发生的变化。
如果商店在安装应用前已经有商品,这些商品不会因为 Webhook 自动出现。因此需要执行历史同步。
在 Gadget 中找到类似:
Shopify Connection
Shopify Shop
Syncs
Data sync
Start sync
选择:
Products
Product Variants
Product Images
然后开始同步。
同步完成后,不要只看“Completed”,还要抽查数据。
建议检查:
Shopify 商品数量
Gadget 商品数量
商品 ID
商品标题
商品状态
商品变体
商品图片
创建时间和更新时间
失败记录
随机打开 3 到 5 个商品,对比 Shopify 和 Gadget 中的数据。
要记住:
历史同步 = 补过去的数据
Webhook = 接收未来的变化
它们是两个不同系统,不能互相替代。
Gadget 是否自动处理分页、速率限制和错误重试,要以当前 Connection 和 Sync 功能实际提供的能力为准。生产环境中仍然要查看同步日志和失败记录。
十二、测试实时 Webhook
Shopify 商品相关的 Webhook topic 通常使用复数形式:
products/create
products/update
products/delete
测试商品创建
在 Shopify Admin 中进入:
Products → Add product
创建测试商品:
Title: Webhook Test T-shirt
Price: 29.99
Status: Active
保存后,检查:
- Shopify 商品是否创建成功
- Webhook 是否发送
- Gadget 日志是否收到通知
- Gadget 商品数据表是否出现记录
- Shopify 商品 ID 是否正确
正常链路应该是:
Shopify 创建商品
↓
products/create
↓
Gadget 接收 Webhook
↓
Gadget 创建或更新数据库记录
不要承诺 Webhook 一定在几秒内到达。Webhook 是异步机制,可能发生延迟或重试。
测试商品修改
将商品标题改为:
Webhook Test T-shirt Updated
保存后,查看 Gadget 中的标题是否更新。
测试商品删除
删除测试商品,再检查 Gadget 中的对应记录。
具体行为取决于模型设计,可能是:
- 删除 Gadget 记录
- 标记为已删除
- 保留记录但更新状态
- 保留同步记录但不再显示
这部分需要在应用设计中明确,不要让读者自行猜测。
十三、为 Webhook 添加后端逻辑
商品同步成功后,可以在记录创建或更新时运行自定义代码。
在 Shopify Product 模型中找到对应 Action,例如:
Create
Update
Shopify webhook action
After action
On success
日志示例:
export const run = async ({ record, logger }) => {
logger.info(
{
productId: record.id,
title: record.title,
},
"Received a Shopify product"
);
};
具体参数和文件结构以 Gadget 自动生成的代码为准。
Webhook 后可以执行:
- 自动检查商品是否有图片
- 根据商品标题打标签
- 将商品发送到 ERP
- 生成 AI 商品描述
- 根据库存发送通知
- 调用第三方 API
- 创建后台任务
- 更新 Shopify 商品
必须处理重复 Webhook
Webhook 可能因为网络问题或处理失败而重试,因此不能假设一个事件只会到达一次。
推荐使用 Shopify 资源 ID 作为稳定标识:
收到商品 Webhook
↓
查找 Shopify product ID
↓
已经存在则更新
↓
不存在才创建
还要防止这种循环:
Shopify 修改商品
↓
Webhook 到达 Gadget
↓
Gadget 又修改 Shopify
↓
Shopify 再次发送 Webhook
解决办法包括:
- 写入前判断字段是否真的发生变化
- 保存自动处理标记
- 使用幂等逻辑
- 不要每次 Webhook 都无条件写回 Shopify
- 将耗时任务放入后台队列
十四、开发 React 嵌入式页面
Gadget 项目通常带有 React 前端,可以做一个简单的商品同步面板。
第一版页面可以包含:
- 当前商店名称
- 商品总数
- 最近同步时间
- 手动同步按钮
- 商品标题列表
- 商品状态
- 错误提示
- Loading 状态
推荐的数据流:
React 页面
↓
Gadget API
↓
Gadget 数据库或后端 Action
↓
Shopify Admin API
不要让 React 直接携带 Shopify Access Token 请求 Shopify。
前端应该只负责:
- 显示数据
- 提交用户操作
- 显示加载状态
- 显示错误信息
真正访问 Shopify 的动作应该由 Gadget 后端完成。
十五、部署前测试清单
安装
- 开发商店可以打开安装流程
- OAuth 可以完成
- 权限显示正确
- 应用显示在 Shopify Admin
- 刷新页面不会重复安装
- 应用不会无限跳转
数据同步
- 历史商品可以同步
- 商品变体可以同步
- 商品图片可以同步
- 同步失败时能看到错误
- 大量数据同步不会静默失败
- 同步可以重试
Webhook
- 新建商品能创建记录
- 修改商品能更新记录
- 删除商品按预期处理
- 重复 Webhook 不会产生重复数据
- 失败 Webhook 会记录日志
- 后端逻辑具备幂等性
安全
- Access Token 不出现在前端
- Client Secret 不提交到 GitHub
- 日志中不打印完整密钥
- 只申请真正需要的 Scope
- 新增权限后可以重新授权
- 卸载应用后旧连接不能继续使用
前端
- Shopify Admin 中可以打开
- 页面刷新正常
- Loading 状态清晰
- 空数据状态清晰
- 错误信息可以理解
- 窄屏下页面基本可用
十六、准备生产环境
Development 和 Production 应该隔离。
如果 Gadget 的两个环境需要独立的:
- Client ID
- Client Secret
- App URL
- OAuth 回调地址
- 数据库
- 环境变量
那么建议创建独立的生产应用:
Product Sync Manager - Production
获取新的:
Production Client ID
Production Client Secret
开发和生产凭据不要混用。
需要注意,创建独立生产 App 是一种隔离方案,不一定是所有项目的强制要求。最终要根据 Shopify App 版本管理和 Gadget 的环境管理方式决定。
十七、配置生产应用
切换 Gadget 到 Production 配置,填写生产凭据。
然后从 Gadget 获取:
Production App URL
Production OAuth Callback URL
回到 Shopify 生产应用中填写:
App URL
Allowed redirection URL
再次检查:
- 使用 HTTPS
- 没有使用开发 URL
- 回调路径完整
- Client ID 和 Client Secret 属于生产应用
- 生产应用权限和 Gadget 功能匹配
- Embedded App 配置正确
- 生产环境变量已经设置
开发数据库和生产数据库通常是分开的,因此开发环境中的测试商品不会自动进入生产环境。
生产安装完成后,需要重新执行:
生产安装
→ 创建 Shop 记录
→ 首次历史同步
→ 测试生产 Webhook
十八、部署到 Gadget Production
在 Gadget 中执行类似:
Deploy to Production
具体按钮名称以当前项目为准。
部署后检查:
- 前端是否可以打开
- 后端是否启动成功
- 数据库迁移是否成功
- 环境变量是否齐全
- Shopify 生产凭据是否正确
- 生产日志是否有报错
- 生产回调地址是否生效
不要只确认“生产页面能访问”,还要真正执行一次:
- 安装生产应用
- 同步历史商品
- 创建一个测试商品
- 修改商品标题
- 删除测试商品
- 检查 Gadget 数据和日志
十九、选择应用分发方式
Custom Distribution
适合:
- 单个商家定制
- 企业内部工具
- 特定客户项目
- 特定组织中的商店
Custom App 不能使用 Shopify Billing API 向商家收费。
Public Distribution
适合:
- 多个独立商家
- SaaS 应用
- 准备提交 Shopify App Store 的应用
公开应用通常需要准备:
- 应用介绍
- 隐私政策
- 服务条款
- 技术支持页面
- 应用截图和图标
- 定价信息
- 数据删除机制
- 审核资料
不要把“生成安装链接”和“应用已经可以公开销售”混为一谈。
如果目标是面向多个独立商家销售,应该一开始就按照 Public App 的要求规划权限、隐私、收费和审核流程。
二十、常见问题排查
OAuth 回调地址不匹配
常见错误:
redirect_uri is not whitelisted
检查:
- Shopify 配置和 Gadget 地址是否完全一致
- 是否少了路径
- 是否误用了开发地址
- 是否使用 HTTPS
- 结尾斜杠是否不同
- 当前 Client ID 是否对应当前环境
安装后无限跳转
可能原因:
- App URL 错误
- Session Token 验证失败
- 开发和生产凭据混用
- Embedded App 配置错误
- 当前商店没有完成安装
- Cookie 或浏览器缓存异常
排查方式:
- 清除站点 Cookie
- 从 Shopify Admin 的 Apps 区域重新打开
- 查看 Gadget 后端日志
- 检查当前环境
- 确认 Client ID 和 App URL 属于同一个应用
商品没有同步
依次检查:
- 是否启用了 Product 模型
- 是否申请了
read_products - 商家是否同意了最新权限
- 是否运行过历史同步
- Webhook 是否成功配置
- Gadget 日志是否有错误
- 查看的是 Development 还是 Production
- 商品是否属于当前测试商店
修改权限后仍然不能使用
新增 Scope 后,旧安装通常不会自动获得权限。
可以尝试:
- 更新 Shopify App 权限
- 更新 Gadget Connection
- 创建或发布新的应用版本
- 重新部署
- 让商家重新授权
- 必要时卸载并重新安装
Webhook 重复执行
不要假设 Webhook 只发送一次。
使用 Shopify 资源 ID作为唯一业务标识,写入前先判断记录是否已经存在。
开发环境正常,生产环境失败
重点检查:
- Production Client ID
- Production Client Secret
- Production App URL
- Production OAuth Callback URL
- 生产环境变量
- 数据库迁移
- 生产 Scopes
- 应用分发状态
- 是否误用了开发安装链接
二十一、最终操作顺序
建议按照这个顺序执行:
- 注册 Shopify Partners 或开发者账号
- 创建带测试数据的开发商店
- 创建 Shopify 开发应用
- 获取开发 Client ID 和 Client Secret
- 创建 Gadget Shopify 项目
- 配置 Development Shopify Connection
- 申请最小 API 权限
- 从 Gadget 复制开发 App URL 和回调地址
- 将 URL 填回 Shopify App 配置
- 启用 Embedded App
- 安装到开发商店
- 确认 Gadget 出现 Shop 记录
- 执行历史商品同步
- 测试
products/create - 测试
products/update - 测试
products/delete - 增加后端业务逻辑
- 开发 React 管理页面
- 测试重复 Webhook 和失败重试
- 创建或配置生产应用
- 设置生产 Client ID 和 Client Secret
- 配置生产 URL 和回调地址
- 部署 Gadget Production
- 安装生产版本
- 执行首次生产同步
- 测试生产 Webhook
- 持续查看日志和同步状态
结语:记住这四件事
1. 历史同步和 Webhook 是两套机制
历史同步负责过去
Webhook 负责未来
2. Session Token 和 Access Token 不是同一个东西
Session Token 用于验证当前页面请求,Access Token 用于服务端访问 Shopify Admin API。
3. Custom App 和 Public App 的收费方式不同
Custom Distribution 适合特定客户,不能直接使用 Shopify Billing API。面向多个独立商家收费时,应规划 Public App。
4. 开发环境成功不代表生产环境成功
生产环境必须重新检查:
凭据
URL
权限
数据库
Webhook
同步
分发方式
完成这些步骤后,你就不只是“创建了一个 Gadget 项目”,而是真正完成了一条可验证的 Shopify App 开发链路:
Shopify
→ OAuth
→ Gadget
→ PostgreSQL
→ Admin API
→ Webhook
→ React
→ Production
这条链路跑通之后,再继续增加订单同步、库存同步、ERP 对接、AI 商品处理或自动化任务,会稳很多。




