From limio-skills
Audits existing Limio component code against official SDK documentation. Use when user asks to "verify SDK usage", "audit Limio code", "check SDK compliance", "review Limio imports", "is this using the SDK correctly", "check limio best practices", or reviews existing component code for correctness. Do NOT use for creating components (use limio-component), creating stories (use limio-story), or deploying (use limio-setup).
How this skill is triggered — by the user, by Claude, or both
Slash command
/limio-skills:limio-sdk-verifyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill to audit existing Limio component code for correct SDK usage, deprecated patterns, security issues, and best practice compliance. This is a **developer-facing** skill for verifying that components use `@limio/sdk` correctly.
Use this skill to audit existing Limio component code for correct SDK usage, deprecated patterns, security issues, and best practice compliance. This is a developer-facing skill for verifying that components use @limio/sdk correctly.
IMPORTANT: When the MCP tool mcp__claude_ai_Limio_External_Docs__searchDocumentation is available, use it to cross-reference findings against the live Limio documentation at https://docs.limio.com/developers/limio-sdk. This provides the most up-to-date SDK guidance and can catch issues not covered by static rules.
CRITICAL — Credential Safety: .limio.json contains OAuth client credentials (client ID + client secret). It MUST be in .gitignore and MUST NEVER be committed to git. Flag this immediately if found tracked or staged.
When auditing a Limio component, check each of the following areas in order:
@limio/sdk (not relative paths)getCurrentBasketId imported from @limio/shop/src/shop/checkout/basket../source/utils/ or other internal pathspackage.json uses default import: import packageData from "./package.json" (NOT import * as packageData)useComponentProps imported from @limio/sdk, getPropsFromPackageJson from @limio/components/helpersconst { offers } = useCampaign() || {}useLimioContext() called with || {} fallbackuseStaticProps() called with || {} fallbackoffer?.data?.attributes?. with optional chainingsubscription.offers[] array (NOT subscription.data.offer)offer?.data?.price?.[0] with null checkoffer?.data?.products with null checkoffer?.data?.attributes?.group__limioxss library or sanitiseHTML from SDKdangerouslySetInnerHTML.limio.json not committed or staged in gitoc-, sp-, ad-) to avoid collisions--my-primary)style attribute@media (max-width: 600px){id, label} objects (not plain strings){id, label, value} objects"type": "color" (no special suffix on ID)"type": "richtext" (no special suffix on ID)__limio_richtext or __limio_color suffixes on prop IDsinitiateCheckout (NOT deprecated addToBasket)orderItems (NOT deprecated basketItems)getCurrentBasketId() before deciding initiateCheckout vs addOfferToBasketbasketLoading state to prevent double submissionspageOptions?.pushToCheckout for auto-navigationposition: fixed or position: absolute check isInPageBuilder from useLimioContext()position: relative when isInPageBuilder is trueThese are the most common deprecated patterns. Flag any occurrence and provide the replacement.
| Deprecated | Replacement | Notes |
|---|---|---|
addToBasket(offer) | initiateCheckout({ order: { orderItems: [{ offer }] } }) | Must also check getCurrentBasketId() first |
basketItems | orderItems | From useBasket() return value |
subscription.data.offer | subscription.offers[] | Legacy field — subscriptions can have multiple offers |
import * as packageData from "./package.json" | import packageData from "./package.json" | Must use default import |
id: "foo__limio_richtext" | id: "foo" with type: "richtext" | Legacy suffix — type field is sufficient |
id: "foo__limio_color" | id: "foo" with type: "color" | Legacy suffix — type field is sufficient |
type: "richText" (camelCase) | type: "richtext" (lowercase) | Modern convention uses lowercase |
addToBasket → initiateCheckout:
// WRONG (deprecated)
const { addToBasket } = useBasket()
addToBasket(offer)
// CORRECT
const { initiateCheckout, addOfferToBasket, navigateToCheckout, pageOptions } = useBasket()
const handleAddToBasket = async (offer) => {
const checkoutId = getCurrentBasketId()
if (!checkoutId) {
await initiateCheckout({ order: { orderItems: [{ offer }] } })
} else {
await addOfferToBasket({ offer })
}
if (pageOptions?.pushToCheckout) {
await navigateToCheckout()
}
}
subscription.data.offer → subscription.offers[]:
// WRONG (legacy)
const offerData = subscription.data.offer
// CORRECT
import { checkActiveOffers, getCurrentOffer } from "@limio/sdk"
const activeOffers = checkActiveOffers(subscription.offers, false)
const currentOffer = getCurrentOffer(subscription)
// Or manually filter:
const standardOffers = subscription.offers?.filter(
o => o.data?.record_subtype !== "discount"
) || []
import * as packageData → default import:
// WRONG
import * as packageData from "./package.json"
// CORRECT
import packageData from "./package.json"
// ANTI-PATTERN
const { offers } = useCampaign() // crashes if useCampaign() returns null/undefined
// FIX
const { offers } = useCampaign() || {}
// ANTI-PATTERN
import { formatPrice } from "../source/utils/helpers"
// FIX — use SDK utilities
import { formatCurrency, formatDisplayPrice } from "@limio/sdk"
// ANTI-PATTERN
<div dangerouslySetInnerHTML={{ __html: offer.data.attributes.offer_features__limio }} />
// FIX
import xss from "xss"
<div dangerouslySetInnerHTML={{ __html: xss(offer?.data?.attributes?.offer_features__limio || "") }} />
// ANTI-PATTERN
<h1>Choose Your Plan</h1>
<button>Subscribe Now</button>
// FIX — use limioProps
const { heading = "Choose Your Plan", ctaText = "Subscribe Now" } = useStaticProps() || {}
<h1>{heading}</h1>
<button>{ctaText}</button>
// ANTI-PATTERN
<button onClick={() => handleAddToBasket(offer)}>Buy</button>
// FIX
const { basketLoading } = useBasket()
<button onClick={() => handleAddToBasket(offer)} disabled={basketLoading}>
{basketLoading ? "Processing..." : ctaText}
</button>
// ANTI-PATTERN
<div style={{ position: "fixed", bottom: 0 }}>Sticky CTA</div>
// FIX
const { isInPageBuilder } = useLimioContext() || {}
<div style={{ position: isInPageBuilder ? "relative" : "fixed", bottom: isInPageBuilder ? "auto" : 0 }}>
Sticky CTA
</div>
// ANTI-PATTERN
"@mui/material": "^6.0.0"
// FIX — use 5.16.12 for React 19 compatibility
"@mui/material": "5.16.12"
// ANTI-PATTERN
"default": ["Monthly", "Annual"]
// FIX
"default": [{ "id": "monthly", "label": "Monthly" }, { "id": "annual", "label": "Annual" }]
/* ANTI-PATTERN — collision risk */
.card { ... }
.header { ... }
/* FIX — prefix with component abbreviation */
.oc-card { ... }
.oc-header { ... }
/* ANTI-PATTERN — no mobile styles */
.oc-grid { display: grid; grid-template-columns: repeat(3, 1fr); }
/* FIX */
.oc-grid { display: grid; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 600px) {
.oc-grid { grid-template-columns: 1fr; }
}
/* ANTI-PATTERN */
.oc-button { background: #635BFF; }
/* FIX */
.oc-button { background: var(--oc-primary, #635BFF); }
// Map color limioProps to CSS variables
<div className="oc-wrapper" style={{ "--oc-primary": primaryColor }}>
import { useComponentProps } from "@limio/sdk"
import { getPropsFromPackageJson } from "@limio/components/helpers"
import packageData from "./package.json"
const defaultComponentProps = getPropsFromPackageJson(packageData)
export function useStaticProps() {
return useComponentProps(defaultComponentProps)
}
const { offers, campaign, addOns, groupValues } = useCampaign() || {}
const { orderItems, basketLoading, initiateCheckout, addOfferToBasket, navigateToCheckout, pageOptions } = useBasket()
const { attributes, loginStatus, loaded } = useUser()
const { subscriptions } = useSubscriptions()
const { isInPageBuilder } = useLimioContext() || {}
const props = useStaticProps() || {}
import { getCurrentBasketId } from "@limio/shop/src/shop/checkout/basket"
const handleAddToBasket = async (offer) => {
const checkoutId = getCurrentBasketId()
if (!checkoutId) {
await initiateCheckout({ order: { orderItems: [{ offer }] } })
} else {
await addOfferToBasket({ offer })
}
if (pageOptions?.pushToCheckout) {
await navigateToCheckout()
}
}
const attributes = offer?.data?.attributes || {}
const displayName = attributes.display_name__limio || "Untitled"
const features = attributes.offer_features__limio || ""
const price = offer?.data?.price?.[0]
const amount = price?.value || 0
const currency = price?.currencyCode || "USD"
import { checkActiveOffers, getCurrentOffer } from "@limio/sdk"
// Get active standard offers (not discounts)
const activeOffers = checkActiveOffers(subscription.offers, false)
// Or get the current offer directly
const currentOffer = getCurrentOffer(subscription)
import xss from "xss"
const sanitizeString = (str) => xss(str || "")
// or
import { sanitiseHTML } from "@limio/sdk"
<div dangerouslySetInnerHTML={{ __html: sanitiseHTML(htmlContent) }} />
When reporting verification results, use this format:
## SDK Verification Report
### Summary
- Issues found: N
- Warnings: N
- Status: PASS / NEEDS FIXES
### Issues (must fix)
1. [FILE:LINE] Description — Replacement
### Warnings (should fix)
1. [FILE:LINE] Description — Recommendation
### Passed Checks
- ✓ Imports correct
- ✓ Null safety present
- ...
references/common-mistakes.md — Detailed before/after examples of every common mistakereferences/sdk-full-reference.md — Complete SDK hook and utility reference with all return shapeslimio-component — Create new componentslimio-story — Create Storybook storieslimio-storybook — Set up the Storybook playgroundlimio-setup — Credentials and deploymentnpx claudepluginhub innovate42/limio-skills --plugin limio-skillsAudits component library APIs for prop naming consistency, breaking changes, TypeScript coverage, default patterns, and design-to-code contract compliance.
Audits Foldkit programs against architecture, conventions, and quality bar. Use when reviewing Foldkit code for anti-patterns, accessibility gaps, or regressions.
Runs pre-submission compliance checks on Shopify app codebases against App Store requirements, surfacing likely issues.