@metrifox/angular-sdk
v2.0.0
Published
Angular SDK for Metrifox - SaaS billing, customer portals, and pricing tables
Readme
MetriFox Angular SDK
A fully-configurable Angular SDK providing ready-to-use components for SaaS and billing platforms including customer portals, pricing tables, and more.
⚠️ Version notice – breaking changes (v2.0.0+)
If you are upgrading from a release before v2.0.0, read this.
From @metrifox/angular-sdk v2.0.0 onward, both Customer Portal and Pricing Table use a new theme structure. The theme API is not backward compatible with pre-2.0.0 versions.
- Theme is now a single object passed via
MetrifoxService.initialize({ theme })with two keys:customerPortalandpricingTable. The previous top-levelpricingTableThemeoption is removed on v2.0.0+; usetheme.pricingTableinstead. - Customer Portal theme uses a new grouped shape:
general,tabs,sections,buttons,lineItems,tables,modals, andplans. Property names and nesting have changed from older versions. - Pricing Table theme now strictly follows the same nested structure as Customer Portal: all plan-related keys must be under
plans(e.g.plans.planCards,plans.planToggle). Top-level plan keys are no longer supported. - Both components accept an optional
themeinput per instance to override or extend the global theme fromMetrifoxService.initialize.
If you were using custom themes before, you will need to migrate your theme objects to the new structure. Omit any keys you don't need; the SDK merges your values with defaults. See the Styling section below for the full theme shapes and examples.
Installation
# using npm
npm install @metrifox/angular-sdk
# or pnpm
pnpm add @metrifox/angular-sdk
# or yarn
yarn add @metrifox/angular-sdkSetup
1. Provide the SDK
Register the SDK providers in your app config:
// app.config.ts (Standalone)
import { ApplicationConfig } from "@angular/core";
import { provideMetrifox } from "@metrifox/angular-sdk";
export const appConfig: ApplicationConfig = {
providers: [
provideMetrifox(), // provides HttpClient + MetrifoxService
],
};2. Initialize the SDK
Before using any components, initialize the SDK once with your Client key:
import { MetrifoxService } from "@metrifox/angular-sdk";
MetrifoxService.initialize({
clientKey: "your-metrifox-client-key",
});3. Import Styles
Add the SDK styles to your angular.json:
{
"styles": ["src/styles.css", "node_modules/@metrifox/angular-sdk/styles.css"]
}Or import in your global styles.css:
@import "@metrifox/angular-sdk/styles.css";Compatible with Angular 17, 18, and 19. All components are standalone (no NgModule required).
Widgets
CustomerPortal
Displays a customizable customer dashboard with plans, subscriptions, billing, credits, and more.
import { Component } from "@angular/core";
import { CustomerPortalComponent, SectionConfig } from "@metrifox/angular-sdk";
@Component({
selector: "app-billing",
standalone: true,
imports: [CustomerPortalComponent],
template: `
<metrifox-customer-portal
[customerKey]="'your-customer-key'"
[sectionsConfig]="sections"
/>
`,
})
export class BillingComponent {
sections: SectionConfig[] = [
{ key: "subscription" },
{ key: "plan" },
{ key: "billingHistory", hidden: true },
];
}Optional theme input: pass a CustomerPortalTheme object to override or extend the global theme from MetrifoxService.initialize for this instance only.
Section Configuration
The sectionsConfig input controls what appears in the portal.
| Property | Type | Description |
| ----------- | ----------------- | --------------------------------------------------- |
| key | SectionKey | Unique key of the section (see list below) |
| hidden | boolean | Hide this section when true |
| component | Type<any> | Replace the default section with your own component |
| props | Record<string, unknown> | Extra props passed to the custom or default section |
Built-in Section Keys
| Key | Description |
| ------------------ | ----------------------------- |
| upcomingInvoice | Displays next invoice details |
| subscription | Active subscription overview |
| creditBalance | Shows user wallet balance |
| entitlementUsage | Displays resource usage |
| paymentOverview | Payment summary and methods |
| billingHistory | List of past transactions |
| plan | Current plan details |
Section Anchors
Each portal section renders inside a <section id="..."> wrapper so you can link directly to segments of a customer portal view. The default anchor IDs are:
| Anchor ID | Section Key |
| -------------------- | ------------------ |
| #upcoming-invoice | upcomingInvoice |
| #subscription | subscription |
| #credit-balance | creditBalance |
| #entitlement-usage | entitlementUsage |
| #payment-overview | paymentOverview |
| #billing-history | billingHistory |
| #plan | plan |
Use these anchors when embedding the SDK or sharing deep links (e.g., https://app.example.com/portal#billing-history).
Pricing Table
Displays subscription plans and one-time purchases in a configurable pricing table component.
import { Component } from "@angular/core";
import { PricingTableComponent } from "@metrifox/angular-sdk";
@Component({
selector: "app-pricing",
standalone: true,
imports: [PricingTableComponent],
template: `
<metrifox-pricing-table
[checkoutUsername]="'your-checkout-username'"
[productKey]="'your-product-key'"
/>
`,
})
export class PricingComponent {}Props
The inputs control how the pricing table is configured.
| Property | Type | Required | Default | Description |
| --------------------- | ------------------ | -------- | ------- | -------------------------------------------------------------------------------- |
| checkoutUsername | string | Yes | — | Unique username used for checkout. This can be found in Settings → Checkout. |
| productKey | string | Yes | — | Unique product identifier. This can be found on the product page. |
| plansOnly | boolean | No | false | Controls whether only subscription plans are rendered. |
| singlePurchasesOnly | boolean | No | false | Controls whether only single purchases are rendered. |
| showTabHeader | boolean | No | true | Controls whether the tab header for switching between offerings is rendered. |
| theme | PricingTableTheme| No | — | Optional theme override for this instance (merged with global theme from MetrifoxService.initialize). |
Note: If both
plansOnlyandsinglePurchasesOnlyarefalseor undefined, both plans and single purchases are displayed.
Styling
Import the SDK's global styles (see Setup step 3).
This is required for proper styling of all components.
Theme configuration (new structure)
Theming is driven by a single theme object passed to MetrifoxService.initialize. It has two top-level keys: customerPortal and pricingTable. Any value you omit falls back to the SDK default. You can also pass an optional theme input to <metrifox-customer-portal> or <metrifox-pricing-table> to override or extend the global theme for that instance.
// Passed to MetrifoxService.initialize({ theme })
theme?: {
customerPortal?: CustomerPortalTheme
pricingTable?: PricingTableTheme
}Removed on v2.0.0+: The previous root-level
pricingTableThemeoption is not supported. Usetheme.pricingTableinstead.
Customer Portal theme (CustomerPortalTheme)
All properties are optional. The shape is grouped by area of the UI:
| Group | Description |
| ----- | ----------- |
| general | Page-level: link color, background, border radius, font family, container padding |
| tabs | Tab bar (e.g. Wallet balance tabs): background, border, active/inactive states |
| sections | Section cards: background, padding, borders, content/summaryBalance sub-styles, header/label/value typography, usage bars, empty text |
| buttons | Primary and secondary buttons: background, border (color/width/radius), typography |
| lineItems | Subscription line items: parentRow/childRow background, border, typography (label/quantity) |
| tables | Tables (e.g. billing history): header/row colors, border, cell padding, expand icon, typography |
| modals | Modal overlay, background, border, close button; header/title/description typography; footer primary/secondary buttons |
| plans | Plan cards when shown in portal: currentPlanCard, planCards (border as { color, width, radius }), planFeatures, planButton, planToggle, planTags |
Example – minimal override:
customerPortal: {
general: { linkColor: "#2563eb", backgroundColor: "#ffffff" },
tabs: {
tabBackground: "#ffffff",
tabBorderColor: "#e5e7eb",
activeTabBackground: "#2563eb",
activeTabTextColor: "#ffffff",
inactiveTabTextColor: "#6b7280",
},
sections: {
background: "#ffffff",
content: { background: "#f4f4f5", borderRadius: "8px" },
header: { fontSize: "16px", fontWeight: "600", color: "#52525b" },
label: { fontSize: "13px", color: "#71717a" },
value: { fontSize: "16px", color: "#52525b" },
},
buttons: {
primary: { backgroundColor: "#2563eb", border: { radius: "8px" }, typography: { color: "#ffffff" } },
secondary: { backgroundColor: "#e4e4e7", typography: { color: "#3f3f46" } },
},
plans: {
planCards: {
background: "#ffffff",
border: { color: "#e5e7eb", width: "1px", radius: "8px" },
header: { background: "#e5e7eb", textColor: "#111827" },
description: { textColor: "#6b7280", textButtonColor: "#2563eb" },
price: { amountColor: "#111827", primaryTextColor: "#6b7280", secondaryTextColor: "#9ca3af" },
},
planButton: { background: "#2563eb", textColor: "#ffffff" },
planToggle: { background: "#e5e7eb", activeBackground: "#1f2937", activeText: "#ffffff", inactiveText: "#6b7280" },
},
}Font customization
The SDK accepts any font-family string in your theme. The SDK applies it via CSS, but your app must load the font (Google Fonts, @font-face, etc.) before the SDK renders.
How it works:
- Load the font in your app (HTML, CSS, or framework-specific):
<!-- Option A: Google Fonts in your index.html <head> -->
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">/* Option B: @font-face in your global CSS */
@font-face {
font-family: 'MyCustomFont';
src: url('/fonts/custom.woff2') format('woff2');
}- Pass the font-family to the SDK theme:
MetrifoxService.initialize({
clientKey: "your-client-key",
theme: {
customerPortal: {
general: {
// Any font-family string works
fontFamily: '"Space Grotesk", "Inter", sans-serif'
// or: 'MyCustomFont, sans-serif'
// or: 'system-ui, -apple-system, sans-serif'
}
}
}
});If no fontFamily is provided, the SDK inherits the font from the host page. This means the SDK works with whatever font your app already uses — no extra configuration needed.
Important: When using Google Fonts or custom fonts, load them in your app before the SDK initializes to prevent flash of unstyled text (FOUT).
Pricing Table theme (PricingTableTheme)
The Pricing Table theme follows the same nested structure as Customer Portal. All plan-related keys must be nested under plans.
| Key | Description |
| --- | ----------- |
| plans | Container for all plan-related styling |
| plans.currentPlanCard | Current-plan highlight: header (background, textColor), gradientColor, description, borderRadius |
| plans.planCards | Card style: background, border ({ color, width, radius }), header, description (textColor, textButtonColor), price (amountColor, primaryTextColor, secondaryTextColor, textButtonColor, background, borderColor) |
| plans.planFeatures | Feature list: textColor, iconColor |
| plans.planButton | CTA button: background, textColor; optional secondaryBackground, secondaryTextColor, textButtonColor |
| plans.planToggle | Monthly/Yearly toggle: background, activeBackground, activeText, inactiveText |
| plans.planTags | Tags (e.g. free trial): freeTrialBackground, freeTrialText |
| tabs | Tabs (e.g. Plans vs Single purchases): inactiveText, activeText, indicator, borderColor |
| checkoutBar | Bottom checkout bar: background, borderColor, textColor, buttonBackground, buttonTextColor |
Example – minimal override:
pricingTable: {
plans: {
planCards: {
background: "#ffffff",
border: { color: "#e5e7eb", width: "1px", radius: "8px" },
header: { background: "#e5e7eb", textColor: "#111827" },
description: { textColor: "#6b7280", textButtonColor: "#2563eb" },
price: { amountColor: "#111827", primaryTextColor: "#6b7280", secondaryTextColor: "#9ca3af" },
},
planButton: { background: "#2563eb", textColor: "#ffffff" },
planToggle: { background: "#e5e7eb", activeBackground: "#1f2937", activeText: "#ffffff", inactiveText: "#6b7280" },
},
tabs: { activeText: "#2563eb", indicator: "#2563eb", borderColor: "#9ca3af" },
checkoutBar: {
background: "#f9fafb",
borderColor: "#e5e7eb",
textColor: "#3f3f46",
buttonBackground: "#2563eb",
buttonTextColor: "#ffffff",
},
}When the Pricing Table is embedded inside the Customer Portal, it automatically uses theme.customerPortal.plans for plan styling so both components stay consistent.
Full example
import { MetrifoxService } from "@metrifox/angular-sdk";
MetrifoxService.initialize({
clientKey: "your-client-key",
theme: {
customerPortal: {
general: { linkColor: "#2563eb", backgroundColor: "#ffffff" },
tabs: {
tabBackground: "#ffffff",
activeTabBackground: "#2563eb",
activeTabTextColor: "#ffffff",
inactiveTabTextColor: "#6b7280",
},
sections: {
background: "#ffffff",
content: { background: "#f4f4f5", borderRadius: "8px" },
},
buttons: {
primary: { backgroundColor: "#2563eb", typography: { color: "#ffffff" } },
},
},
pricingTable: {
plans: {
planCards: { background: "#ffffff", border: { color: "#e5e7eb", radius: "8px" } },
planButton: { background: "#2563eb", textColor: "#ffffff" },
},
tabs: { activeText: "#2563eb", indicator: "#2563eb" },
checkoutBar: { buttonBackground: "#2563eb", buttonTextColor: "#ffffff" },
},
},
});Per-component overrides (optional):
<metrifox-customer-portal
[customerKey]="'cust_123'"
[theme]="{ general: { linkColor: '#1d4ed8' } }"
/>
<metrifox-pricing-table
[checkoutUsername]="'checkout_user'"
[productKey]="'prod_key'"
[theme]="{ plans: { planCards: { background: '#f8fafc' } } }"
/>Migration from React SDK
| React | Angular |
| ----------------------- | ------------------------------ |
| metrifoxInit() | MetrifoxService.initialize() |
| <CustomerPortal /> | <metrifox-customer-portal> |
| <PricingTable /> | <metrifox-pricing-table> |
| customerKey prop | [customerKey] input |
| onPlanSelect callback | (planSelected) output |
| theme prop | [theme] input |
Local Development
Using yalc
For local SDK testing:
# In SDK project
pnpm build
npx yalc publish
# In consuming app
npx yalc add @metrifox/angular-sdk
npm installAuto-update during development
# In SDK project
pnpm build # rebuild
npx yalc publish # re-publish to yalc
# In consuming project
npx yalc update @metrifox/angular-sdkClean up
npx yalc remove @metrifox/angular-sdk
npm installSupport
📘 Full Documentation: For detailed guides, API references, and live examples, visit docs.metrifox.com.
📄 License
MIT © MetriFox
