PayPal Advanced Card Fields — Custom Checkout Developer Indonesia
Lo developer Indonesia. Mau checkout card dengan styling custom. PayPal Smart Button terlalu rigid. Standard iframe kurang flexible. Solution: PayPal Advanced Card Fields.
PayPal Advanced Card Fields = flexible card input dengan control penuh styling. Tokenization secure. 3DS challenge supported. PCI SAQ-A scope (lowest compliance).
Panduan ini bahas cara implement Advanced Card Fields buat Indonesia developer.
Singkatnya: Advanced Card Fields = custom card UI + secure tokenization + 3DS. PCI SAQ-A, full styling control. Butuh bantu integrate? Chat ChatBot Cell.
1. Apa Itu Advanced Card Fields?
Konsep
- PayPal Hosted Fields (sebelumnya): iframe-based, mid customization
- Advanced Card Fields (modern): flexible, individual card elements
- Pattern mirip Stripe Elements: individual input untuk number, CVV, expiry
Component
- Card Number Field: separate input
- Expiry Field: separate input (MM/YY)
- CVV Field: separate input
- Name Field: optional
- Postal Code: optional (AVS)
Architecture
[Your Checkout Page]
↓
[Individual iframes per field]
↓ (PayPal-hosted, secure)
[Tokenization]
↓ (server-side)
[PayPal API: create order with tokenized card]
↓
[3DS Challenge (if required)]
↓
[Payment Capture]
PCI Compliance Scope
- SAQ-A (lowest): card data nggak pernah touch your server
- Iframes PayPal-hosted
- Tokenization secure
- Best for developer Indonesia
2. Why Advanced Card Fields?
Pro vs PayPal Smart Button
- Full styling control: match your brand
- Custom layout: any grid, any order
- Individual validation: per field feedback
- Native form feel: not "popup" experience
- 3DS integration: explicit control
Pro vs Stripe Elements
- PayPal ecosystem: combine PayPal + card + Apple Pay
- PayPal buyer protection: trusted brand
- Single integration: multiple payment method
Con
- Slightly more code than Smart Button
- Learning curve: understand iframe pattern
- Initial setup: 1-2 hari extra vs Smart Button
3. Setup PayPal Account
Step 1: PayPal Business Account
- Verified with KTP + NPWP + bank
- Upgrade ke Payments Pro (optional, kalau perlu advanced feature)
- Atau Payments Standard cukup buat Advanced Card Fields
Step 2: Create REST App
- Visit developer.paypal.com
- My Apps → Create App
- Name: "my-store-card"
- Type: Merchant
- Features: enable PayPal Checkout
- Save → dapat Client ID + Secret
Step 3: Enable Advanced Card Fields
- App → Accept Payments → Card Payments
- Enable: ✅ Advanced Card Fields
- Enable: ✅ 3D Secure
- Save
4. Client SDK Setup
Install
npm install @paypal/paypal-js
Loader
// lib/paypal-loader.ts
import { loadScript } from "@paypal/paypal-js";
let paypalPromise: Promise<any> | null = null;
export function loadPayPal() {
if (!paypalPromise) {
paypalPromise = loadScript({
clientId: process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID!,
components: "card-fields",
currency: "USD",
intent: "capture",
});
}
return paypalPromise;
}
5. Card Fields Component
// app/components/CardFields.tsx
"use client";
import { useEffect, useState, useRef } from "react";
import { loadPayPal } from "@/lib/paypal-loader";
export default function CardFields({ orderId, onApprove }: {
orderId: string;
onApprove: (data: any) => void;
}) {
const [cardField, setCardField] = useState<any>(null);
const numberRef = useRef<HTMLDivElement>(null);
const cvvRef = useRef<HTMLDivElement>(null);
const expiryRef = useRef<HTMLDivElement>(null);
const nameRef = useRef<HTMLInputElement>(null);
useEffect(() => {
let card: any;
async function init() {
const paypal = await loadPayPal();
card = paypal.CardFields({
style: {
input: {
"font-size": "16px",
"font-family": "Inter, sans-serif",
color: "#1a1a1a",
},
".invalid": { color: "#dc2626" },
".valid": { color: "#16a34a" },
},
cardholderName: { placeholder: "Cardholder Name", required: true },
number: { placeholder: "Card Number" },
cvv: { placeholder: "CVV" },
expirationDate: { placeholder: "MM/YY" },
createOrder: async () => orderId,
onApprove: (data) => onApprove(data),
onError: (err) => console.error("Card error:", err),
});
if (card.isEligible()) {
card.NameField({ el: "#card-name" }).render("#card-name-container");
card.NumberField({ el: "#card-number" }).render("#card-number-container");
card.ExpiryField({ el: "#card-expiry" }).render("#card-expiry-container");
card.CVVField({ el: "#card-cvv" }).render("#card-cvv-container");
setCardField(card);
}
}
init();
return () => card?.close?.();
}, [orderId]);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (cardField) {
const result = await cardField.submit({
cardholderName: nameRef.current?.value,
});
if (!result) {
// Validation failed
}
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label>Cardholder Name</label>
<div id="card-name-container">
<input id="card-name" ref={nameRef} className="w-full p-3 border rounded" />
</div>
</div>
<div>
<label>Card Number</label>
<div id="card-number-container">
<div id="card-number" />
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label>Expiry</label>
<div id="card-expiry-container">
<div id="card-expiry" />
</div>
</div>
<div>
<label>CVV</label>
<div id="card-cvv-container">
<div id="card-cvv" />
</div>
</div>
</div>
<button type="submit" className="w-full p-3 bg-yellow-400 text-black rounded">
Pay Now
</button>
</form>
);
}
6. Server-Side Create Order
// app/api/paypal/create-card-order/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getAccessToken } from "@/lib/paypal/auth";
export async function POST(req: NextRequest) {
const { items, currency = "USD" } = await req.json();
const total = items.reduce(
(sum: number, i: { amount: number; quantity: number }) =>
sum + i.amount * i.quantity,
0
);
const token = await getAccessToken();
const res = await fetch(
`${process.env.PAYPAL_API_BASE}/v2/checkout/orders`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
"PayPal-Request-Id": crypto.randomUUID(),
},
body: JSON.stringify({
intent: "CAPTURE",
purchase_units: [{
amount: { currency_code: currency, value: total.toFixed(2) },
}],
payment_source: {
card: {
attributes: {
verification: { method: "SCA_WHEN_REQUIRED" },
},
},
},
}),
}
);
const order = await res.json();
return NextResponse.json({ id: order.id });
}
7. 3D Secure (SCA) Integration
Promo seru yang cocok buat kamu
Penawaran pilihan dari mitra kami — klik buat lihat detail.
Mengandung link afiliasi. Baca disclaimer.
Why 3DS?
- EU regulation: PSD2 SCA mandatory
- Fraud reduction: 60-80% fraud drop
- Liability shift: dari merchant ke bank (post-3DS)
PayPal 3DS Strategy
- SCA_WHEN_REQUIRED: PayPal decide when to challenge
- SCA_ALWAYS: always challenge (highest security)
- SCA_NEVER: never challenge (deprecated buat EU)
Code Trigger
const card = paypal.CardFields({
// ...
payment_source: {
card: {
attributes: {
verification: { method: "SCA_WHEN_REQUIRED" },
},
},
},
});
User Experience
- User fill card details
- Click "Pay"
- PayPal detect if 3DS needed
- If yes: redirect ke bank challenge page (OTP, biometric, dll)
- User complete challenge
- Redirect back to checkout
- Capture payment
8. Capture with 3DS Result
// app/api/paypal/capture-card-order/route.ts
export async function POST(req: NextRequest) {
const { orderID } = await req.json();
const token = await getAccessToken();
const res = await fetch(
`${process.env.PAYPAL_API_BASE}/v2/checkout/orders/${orderID}/capture`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
);
const data = await res.json();
if (data.status === "COMPLETED") {
return NextResponse.json({ success: true, capture: data });
} else if (data.status === "PAYER_ACTION_REQUIRED") {
// 3DS challenge needed
return NextResponse.json({
success: false,
actionRequired: true,
links: data.links,
});
} else {
return NextResponse.json({ success: false, error: data }, { status: 400 });
}
}
9. Validation + Error Handling
Field Validation
const card = paypal.CardFields({
inputEvents: {
onChange: (data) => {
// data.fields = { 'number': { isValid: true, isEmpty: false }, ... }
const numberField = document.getElementById("card-number-icon");
if (data.fields.cardNumber.isValid) {
numberField?.classList.add("valid");
} else {
numberField?.classList.remove("valid");
}
},
onFocus: (data) => {
const container = document.querySelector(`#${data.containerId}-container`);
container?.classList.add("focused");
},
onBlur: (data) => {
const container = document.querySelector(`#${data.containerId}-container`);
container?.classList.remove("focused");
},
},
});
Error Display
async function handleSubmit() {
const result = await cardField.submit();
if (!result) {
// Show field-level errors
Object.entries(cardField.getState().fields).forEach(([field, state]: any) => {
if (!state.isValid && !state.isEmpty) {
const errorEl = document.getElementById(`${field}-error`);
errorEl!.textContent = state.message || "Invalid";
}
});
}
}
10. Studi Kasus — Indonesia SaaS Implement Advanced Card Fields
Profil: Bagus, founder Indonesia SaaS subscription. Tech: Next.js 16 + PostgreSQL. Pricing $29/month + $290/year.
Reason Pilih Advanced Card Fields
- Smart Button kurang flexible untuk monthly recurring
- Stripe belum support Indonesia native
- Mau styling 100% match dengan SaaS brand
- Need 3DS untuk EU customer (PSD2 compliance)
Implementation
- Day 1-2: SDK setup + loader
- Day 3-4: Card Fields component dengan styling custom
- Day 5: 3DS integration + challenge handling
- Day 6: Validation + error UX
- Day 7: End-to-end test
- Day 8: Go-live
Styling Decision
- Border highlight:
#FFD700(brand yellow) - Focus state:
#FACC15with glow - Error:
#dc2626red border - Success:
#16a34agreen border - Typography: Inter 16px (readable)
- Layout: 2-column (number full, expiry + CVV side-by-side)
Result Month 1
- Conversion rate: 4.8% (vs Smart Button 3.9%)
- 3DS challenge triggered: 12% (EU user)
- 3DS success rate: 88%
- Card fraud: 0 cases
- Customer feedback: positive ("Checkout-nya clean")
Lesson: Advanced Card Fields = +0.9% conversion + full styling control + 3DS compliance.
11. PCI Compliance Scope
SAQ-A (Lowest)
- Card data nggak pernah touch server lo
- All card input via PayPal iframe
- Tokenization PayPal side
- Lo only handle token (no raw PAN)
SAQ-A-EP
- If you customize card form (JavaScript touches card field)
- Slightly more strict
Avoid SAQ-D
- Kalau card data touch your server = SAQ-D
- 300+ requirement, audit expensive ($50K+)
With Advanced Card Fields
- Scope: SAQ-A
- Audit: self-assessment (~$0)
- Liability: PayPal handle breach
12. Common Mistake Developer
Mistake 1: Try Access Iframe Content
Mistake: query iframe innerHTML buat card number. Fix: Nggak bisa. Iframe cross-origin. Only PayPal can access.
Mistake 2: Custom Styling Outside style Option
Mistake: CSS inject ke .paypal-input direct.
Fix: Use PayPal style config option. Otherwise ignored.
Mistake 3: Skip 3DS Handling
Mistake: nggak handle PAYER_ACTION_REQUIRED.
Fix: always check status, redirect to challenge link.
Mistake 4: Test Production Card
Mistake: test real card di production env. Fix: always sandbox first. Test card list (4032035796248364 dll).
Mistake 5: Nggak Verify Webhook
Mistake: trust client-side capture. Fix: always webhook server-side verify.
Mistake 6: Forgetting Edge Case
Mistake: assume all card smooth. Fix: handle decline (4000000000000002), insufficient funds, expired, dll.
Mistake 7: Skip Idempotency
Mistake: retry capture tanpa idempotency key. Fix: PayPal-Request-Id always.
13. Tips Pro Advanced Card Fields
1. Style Consistent dengan Brand
- Color, font, border match
- Loading state spinner
- Success state animation
2. Real-time Validation
- Show ✓ saat field valid
- Show ✗ saat invalid
- Disable submit kalau ada invalid field
3. Detect Card Type
- PayPal auto-detect Visa, Mastercard, Amex, JCB
- Show card brand icon
- Adjust CVV length (3 untuk Visa, 4 untuk Amex)
4. Save Card (Vault)
- PayPal Vault buat tokenized card storage
- Return customer: 1-click pay
- Reduce friction
5. Implement Fraud Detection
- PayPal Risk API
- Custom rules (block IP, email domain)
- AVS + CVV check
6. Multi-Currency Support
- Show price in user currency
- Process in their currency
- Avoid FX loss
7. Handle Decline Gracefully
- Specific error message ("Card declined, try another")
- Suggest alternative ("Pakai PayPal balance? Apple Pay?")
- Save cart buat retry
14. Studi Kasus — Indonesia E-commerce Implement
Profil: TokoBungaJakarta, e-commerce flower delivery. Existing PayPal Smart Button. Add Advanced Card Fields buat higher conversion.
Before
- Smart Button only
- Conversion: 2.8% visit → paid
- Customer feedback: "checkout ribet, kebanyakan popup"
After Implementation
- Advanced Card Fields inline
- Conversion: 3.5% (+25%)
- Customer feedback: "checkout-nya cepat dan clean"
Specific Improvements
- Card number auto-format (4-4-4-4)
- Expiry auto MM/YY
- CVV show/hide toggle
- Real-time validation
- Saved card buat return customer
Revenue Impact
- Conversion lift: +25%
- Monthly order: 100 → 125
- AOV: Rp 350K
- Additional monthly: 25 × Rp 350K = Rp 8.75 juta
- Annual: Rp 105 juta added revenue
Lesson: Small UX improvement = significant revenue impact.
15. Security Best Practice
1. Always HTTPS
- SSL wajib (Let's Encrypt free)
- HSTS header
- Redirect HTTP → HTTPS
2. Content Security Policy
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.paypal.com https://www.gstatic.com;
frame-src https://www.paypal.com https://js.braintreegateway.com;
style-src 'self' 'unsafe-inline' https://www.paypal.com;
3. Verify Webhook Signature
- Always verify PayPal webhook
- Prevent forged webhook attack
- Reject invalid signature
4. Don't Log Card Data
- Never log raw PAN, CVV
- Use PayPal token only
- Redact sensitive fields
5. Audit Access
- Who has access to PayPal dashboard
- API credentials
- Multi-user dengan permission
6. Monitor Fraud Pattern
- Set up fraud alert
- Block suspicious IP
- Manual review high-value order
16. Tools Stack Developer
Client SDK
- @paypal/paypal-js: official loader
- @paypal/react-paypal-js: React wrapper (kalau pake Smart Button juga)
Server
- Native fetch: minimal, modern
- paypal-rest-sdk: legacy (deprecated)
Testing
- Cypress: E2E
- Playwright: alternative
- Sandbox cards: PayPal provide
Monitoring
- Sentry: error tracking
- Datadog: APM
- LogRocket: session replay
17. Checklist Implementasi Advanced Card Fields
Persiapan
- PayPal Business verified
- REST App dibuat
- Advanced Card Fields enabled
- 3DS verification enabled
Client Setup
- Install
@paypal/paypal-js - Loader utility
- CardFields component
- Styling match brand
Server Setup
- OAuth2 token cache
- Create order endpoint
- Capture endpoint with 3DS handling
- Webhook handler + verify
Testing
- Sandbox test semua card scenario
- 3DS challenge flow
- Decline scenarios
- Multi-currency
- Mobile + desktop
Go-Live
- Switch env credentials
- Test $0.01 real
- Monitor first 100 transactions
- Setup alert webhook failure
- Document runbook
18. FAQ Advanced Card Fields Indonesia
Q: Bisanya Indonesia developer pakai Advanced Card Fields?
A: Bisa. Global feature. No restriction.
Q: Berapa fee transaction?
A: Standar PayPal fee 4.4% + $0.30 international. Same with Smart Button.
Q: Apakah perlu PCI DSS audit?
A: Nggak. SAQ-A self-assessment. PayPal handle card data.
Q: Bisanya dengan Visa/Mastercard Indonesia?
A: Bisa. Card yang issued Indonesia support.
Q: Bisanya recurring subscription?
A: Bisa. Pakai PayPal Vault buat tokenized card storage + recurring.
Q: 3DS wajib Indonesia?
A: Nggak wajib (regulasi Indonesia beda). Tapi recommended buat EU customer.
19. Mitos vs Fakta Advanced Card Fields
Mitos 1: "Advanced Card Fields Ribet"
Fakta: Setup 1-2 hari. ROI cepat via conversion lift.
Mitos 2: "PCI Compliance Mahal"
Fakta: SAQ-A self-assessment. $0 audit.
Mitos 3: "Smart Button Cukup"
Fakta: Smart Button conversion lebih rendah. Custom UI lebih optimal.
Mitos 4: "3DS Bikin Conversion Drop"
Fakta: 3DS modern (frictionless) drop <5%. Worth fraud reduction.
Mitos 5: "Indonesia Card Nggak Support"
Fakta: Visa/Mastercard issued Indonesia support penuh.
20. Verdict — Advanced Card Fields = Premium Checkout Experience
Advanced Card Fields = pilihan premium buat Indonesia developer yang mau full control + higher conversion + 3DS compliance.
Yang paling critical:
- PCI SAQ-A scope (low compliance)
- Styling full control (brand consistency)
- 3DS handling (SCA_WHEN_REQUIRED)
- Real-time validation (UX)
- Webhook verify (security)
Yang perlu di-avoid:
- Access iframe content
- Skip 3DS handling
- Test real card di production
- Skip webhook verify
- Hardcode credential
Yang always do:
- Sandbox test lengkap
- Save card (Vault) buat return customer
- Fraud detection
- Monitor conversion rate
- Update SDK rutin
ChatBot Cell siap bantu setup Advanced Card Fields + styling custom + 3DS integration + production deploy. Plus AI Chatbot buat auto-handle 3DS challenge + alert fraud pattern + recover failed payment. Konsultasi gratis.







