Building a Shopify App with Remix and React: Lessons Learned
Practical lessons from building LogoBadge, a Shopify app that displays Google Reviews badges, using Shopify's Remix framework.
Why Shopify Moved to Remix
Shopify's app development framework has evolved significantly. The current recommended approach uses Remix with React, replacing the older Next.js-based template. LogoBadge, our Google Reviews badge app, was built entirely on this new stack.
What LogoBadge Does
LogoBadge adds a Google Reviews badge directly under a Shopify store's logo. When customers see a real Google rating on every page, it builds trust instantly. The app:
- Fetches review data from the Google Places API
- Renders a customizable badge via Liquid theme extensions
- Stores merchant settings in Prisma/SQLite (development) or PostgreSQL (production)
Setting Up the Shopify Remix App
Shopify provides a CLI to scaffold the app:
npx @shopify/create-app@latest
This generates a Remix app with:
- OAuth authentication built in
- Session management via Prisma
- App Bridge integration for the admin interface
- Webhook handling boilerplate
Project Structure
app/
routes/
app._index.tsx # Main dashboard
app.settings.tsx # Settings page
webhooks.tsx # Webhook handler
components/
BadgePreview.tsx
SettingsForm.tsx
extensions/
logo-badge/
blocks/
badge.liquid # Theme extension block
locales/
en.default.json
prisma/
schema.prisma
Theme App Extensions
The badge itself lives as a Theme App Extension — a Liquid block that merchants can place in their theme using the customizer. No code injection or theme editing required.
{% comment %} blocks/badge.liquid {% endcomment %}
{% if block.settings.place_id != blank %}
<div class="logobadge-container"
style="text-align: {{ block.settings.alignment }};">
<a href="{{ block.settings.review_url }}"
target="_blank" rel="noopener">
<div class="logobadge-badge">
<img src="{{ 'google-logo.svg' | asset_url }}"
alt="Google" width="16" height="16">
<span class="logobadge-rating">
{{ block.settings.rating }}
</span>
<span class="logobadge-stars">
{% for i in (1..5) %}
{% if i <= block.settings.rating %}
★
{% else %}
☆
{% endif %}
{% endfor %}
</span>
<span class="logobadge-count">
({{ block.settings.review_count }})
</span>
</div>
</a>
</div>
{% endif %}
Google Places API Integration
Fetching review data requires the Places API (New):
async function fetchGoogleReviews(placeId: string) {
const response = await fetch(
`https://places.googleapis.com/v1/places/${placeId}`,
{
headers: {
'X-Goog-Api-Key': process.env.GOOGLE_PLACES_API_KEY!,
'X-Goog-FieldMask': 'rating,userRatingCount,googleMapsUri'
}
}
);
const data = await response.json();
return {
rating: data.rating,
reviewCount: data.userRatingCount,
mapsUrl: data.googleMapsUri
};
}
Prisma for Data Persistence
Merchant settings are stored using Prisma:
model BadgeSettings {
id String @id @default(cuid())
shop String @unique
placeId String
rating Float @default(0)
reviewCount Int @default(0)
alignment String @default("center")
lastSynced DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Key Lessons from Building with Shopify Remix
1. App Bridge Is Mandatory
Shopify requires embedded apps to use App Bridge for navigation, modals, and toasts. Don't fight it — embrace the Polaris design system.
2. Webhook Verification Is Critical
Shopify signs webhook payloads with HMAC. Always verify:
import crypto from 'crypto';
function verifyWebhook(body: string, hmacHeader: string) {
const hash = crypto
.createHmac('sha256', process.env.SHOPIFY_API_SECRET!)
.update(body)
.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(hmacHeader)
);
}
3. Scopes Should Be Minimal
Request only the API scopes you actually need. LogoBadge only needs read_themes and write_themes — nothing more. Merchants are wary of apps that request excessive permissions.
4. Testing Requires a Development Store
You can't test Shopify apps locally against production stores. Create a development store through your Partner account and test everything there first.
Deployment
Shopify apps need a publicly accessible URL. Railway provides:
- Automatic HTTPS (required by Shopify)
- PostgreSQL for production database
- Environment variable management
- Simple deployments via GitHub integration
Conclusion
The Shopify Remix stack is opinionated but productive. Once you understand the conventions — App Bridge, Polaris, Theme Extensions, and webhook handling — you can build and ship apps quickly. LogoBadge went from concept to published in the Shopify App Store in under two weeks.
Related Project
LogoBadge - Google ReviewsShopify app that automatically displays a Google Reviews badge directly under the store logo, showing live star ratings and review counts from Google Business Profile.