Artist Analytics API
The Artist Analytics API provides performance metrics for artists selling in the gallery. Track sales, revenue, top products, and referral conversions.
Authentication
Requires Supabase authentication with artist organization membership:
Authorization: Bearer <access_token>
Endpoints
Get Artist Analytics
Retrieves comprehensive analytics for an artist's gallery performance.
Endpoint: GET /api/gallery/artist/analytics
Authentication: Required (Supabase JWT)
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Artist's organization UUID |
start_date | string | No | Start date (ISO 8601, default: 30 days ago) |
end_date | string | No | End date (ISO 8601, default: now) |
Response:
{
"analytics": {
"overview": {
"totalOrders": 24,
"totalRevenue": 2850.00,
"galleryCommission": 342.00,
"artistPayout": 2508.00,
"averageOrderValue": 118.75,
"totalItemsSold": 42
},
"ordersByStatus": {
"paid": 3,
"processing": 2,
"shipped": 12,
"delivered": 7
},
"topProducts": [
{
"productId": "prod_001",
"productName": "Abstract Painting #5",
"totalRevenue": 900.00,
"unitsSold": 6,
"averagePrice": 150.00
},
{
"productId": "prod_002",
"productName": "Ceramic Vase",
"totalRevenue": 640.00,
"unitsSold": 8,
"averagePrice": 80.00
}
],
"referrals": {
"totalReferrals": 42,
"conversions": 8,
"conversionRate": 19.05,
"attributedRevenue": 680.00
},
"timeline": [
{
"date": "2024-01-01",
"orders": 3,
"revenue": 425.00
},
{
"date": "2024-01-02",
"orders": 5,
"revenue": 680.00
}
],
"dateRange": {
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-31T23:59:59Z"
}
}
}
Response Fields:
Overview
| Field | Type | Description |
|---|---|---|
totalOrders | number | Number of orders containing artist's items |
totalRevenue | number | Total product revenue (before commission) |
galleryCommission | number | 12% gallery commission |
artistPayout | number | 88% payout to artist |
averageOrderValue | number | Average revenue per order |
totalItemsSold | number | Total quantity of items sold |
Orders by Status
| Status | Description |
|---|---|
paid | Payment received, awaiting fulfillment |
processing | Artist is preparing items |
shipped | Artist has shipped items |
delivered | Items delivered to customer |
Top Products
| Field | Type | Description |
|---|---|---|
productId | string | Product UUID |
productName | string | Product name |
totalRevenue | number | Revenue from this product |
unitsSold | number | Quantity sold |
averagePrice | number | Average price per unit |
Referrals
| Field | Type | Description |
|---|---|---|
totalReferrals | number | Gallery visitors who clicked through to artist store |
conversions | number | Referrals who purchased within 30 days |
conversionRate | number | Conversion percentage |
attributedRevenue | number | Revenue from attributed conversions |
Note: Attributed revenue is from artist's individual store, not gallery sales. Artist keeps 100% (minus Stripe fees) on attributed sales.
Timeline
Daily breakdown of orders and revenue within the date range:
| Field | Type | Description |
|---|---|---|
date | string | Date (YYYY-MM-DD) |
orders | number | Orders on this date |
revenue | number | Revenue on this date |
Example Request:
curl "https://gallery.artbase.studio/api/gallery/artist/analytics?org_id=org_abc123" \
-H "Authorization: Bearer <token>"
Example with Date Range:
curl "https://gallery.artbase.studio/api/gallery/artist/analytics?org_id=org_abc123&start_date=2024-01-01&end_date=2024-01-31" \
-H "Authorization: Bearer <token>"
Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | Organization ID required | Missing org_id parameter |
| 401 | Unauthorized | Missing or invalid token |
| 403 | Forbidden | User not member of organization |
Understanding the Metrics
Revenue Calculation
// Per-order calculation
const productRevenue = orderItems.reduce(
(sum, item) => sum + (item.price * item.quantity),
0
);
const galleryCommission = productRevenue * 0.12;
const artistPayout = productRevenue * 0.88;
// Artist receives payout via Stripe Transfer
// Gallery commission + Stripe fees paid by customer
Example: $100 product
| Component | Amount |
|---|---|
| Product revenue | $100.00 |
| Gallery commission (12%) | $12.00 |
| Artist payout (88%) | $88.00 |
Customer pays: ~$115 (includes Stripe fees)
Referral Attribution
Referral tracking works as follows:
- User visits gallery - Views artist's work on gallery.artbase.studio
- Clicks through - Visits artist's individual store (artist.artbase.studio)
- Cookie set - 30-day attribution cookie stored
- Purchase within 30 days - Tracked as conversion
- Artist keeps 100% - No gallery commission on attributed sales
Benefits for Artists:
- Use gallery as marketing/discovery channel
- Keep full revenue on direct sales
- Build direct customer relationships
Top Products Algorithm
Products ranked by total revenue:
const topProducts = products
.map(product => ({
...product,
totalRevenue: product.orders.reduce(
(sum, order) => sum + (order.price * order.quantity),
0
),
unitsSold: product.orders.reduce(
(sum, order) => sum + order.quantity,
0
),
}))
.sort((a, b) => b.totalRevenue - a.totalRevenue)
.slice(0, 10); // Top 10
Use Cases
Artist Dashboard
Display key metrics on artist's dashboard:
import { useEffect, useState } from 'react';
export function ArtistDashboard({ orgId, token }) {
const [analytics, setAnalytics] = useState(null);
useEffect(() => {
async function fetchAnalytics() {
const res = await fetch(
`/api/gallery/artist/analytics?org_id=${orgId}`,
{
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await res.json();
setAnalytics(data.analytics);
}
fetchAnalytics();
}, [orgId, token]);
if (!analytics) return <div>Loading...</div>;
const { overview, topProducts, referrals } = analytics;
return (
<div>
<h1>Gallery Performance</h1>
<div className="metrics">
<div className="metric">
<h3>Total Revenue</h3>
<p>${overview.totalRevenue.toFixed(2)}</p>
</div>
<div className="metric">
<h3>Your Payout</h3>
<p>${overview.artistPayout.toFixed(2)}</p>
</div>
<div className="metric">
<h3>Orders</h3>
<p>{overview.totalOrders}</p>
</div>
<div className="metric">
<h3>Items Sold</h3>
<p>{overview.totalItemsSold}</p>
</div>
</div>
<h2>Top Products</h2>
<table>
<thead>
<tr>
<th>Product</th>
<th>Revenue</th>
<th>Units Sold</th>
</tr>
</thead>
<tbody>
{topProducts.map(product => (
<tr key={product.productId}>
<td>{product.productName}</td>
<td>${product.totalRevenue.toFixed(2)}</td>
<td>{product.unitsSold}</td>
</tr>
))}
</tbody>
</table>
<h2>Referral Performance</h2>
<p>
Gallery referrals: {referrals.totalReferrals}
<br />
Conversions: {referrals.conversions} ({referrals.conversionRate.toFixed(1)}%)
<br />
Attributed revenue: ${referrals.attributedRevenue.toFixed(2)}
</p>
</div>
);
}
Revenue Chart
Visualize daily revenue:
import { Line } from 'react-chartjs-2';
export function RevenueChart({ timeline }) {
const data = {
labels: timeline.map(day => day.date),
datasets: [
{
label: 'Daily Revenue',
data: timeline.map(day => day.revenue),
borderColor: 'rgb(75, 192, 192)',
tension: 0.1,
},
],
};
return <Line data={data} />;
}
Export Analytics
Download analytics as CSV:
async function exportAnalytics(orgId: string, token: string) {
const res = await fetch(
`/api/gallery/artist/analytics?org_id=${orgId}`,
{
headers: { Authorization: `Bearer ${token}` },
}
);
const { analytics } = await res.json();
const csv = [
['Metric', 'Value'],
['Total Orders', analytics.overview.totalOrders],
['Total Revenue', analytics.overview.totalRevenue],
['Gallery Commission', analytics.overview.galleryCommission],
['Artist Payout', analytics.overview.artistPayout],
['Average Order Value', analytics.overview.averageOrderValue],
['Total Items Sold', analytics.overview.totalItemsSold],
[''],
['Top Products', ''],
['Product', 'Revenue', 'Units Sold'],
...analytics.topProducts.map(p => [
p.productName,
p.totalRevenue,
p.unitsSold,
]),
]
.map(row => row.join(','))
.join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `analytics-${orgId}-${new Date().toISOString()}.csv`;
a.click();
}
Optimization Tips
Improve Conversion Rate
If referral conversion rate is low (<10%), try:
- Optimize store: Ensure artist store has good product photos, descriptions
- Offer exclusives: Products only available on artist store (not gallery)
- Email list: Collect emails from gallery visitors for remarketing
- Social proof: Add reviews, testimonials to artist store
Boost Top Products
Identify what's selling well and:
- Create variations: Offer different sizes, colors of top sellers
- Cross-promote: Bundle top products with slower movers
- Increase inventory: Ensure top products stay in stock
- Gallery features: Request spotlight or collection placement for top products
Increase Average Order Value
Encourage larger purchases:
- Bundles: Offer product sets at slight discount
- Free shipping threshold: "Free shipping on orders $75+"
- Upsells: Suggest complementary products during checkout
Data Retention
Analytics data is stored indefinitely but:
- Real-time updates: Metrics update within 1 hour of order status change
- Historical accuracy: Past data never changes (no retroactive adjustments)
- Date range limits: API returns max 1 year of data per query
For longer time ranges, make multiple API calls:
async function getYearlyAnalytics(orgId: string, year: number) {
const quarters = [
{ start: `${year}-01-01`, end: `${year}-03-31` },
{ start: `${year}-04-01`, end: `${year}-06-30` },
{ start: `${year}-07-01`, end: `${year}-09-30` },
{ start: `${year}-10-01`, end: `${year}-12-31` },
];
const results = await Promise.all(
quarters.map(q =>
fetch(
`/api/gallery/artist/analytics?org_id=${orgId}&start_date=${q.start}&end_date=${q.end}`,
{ headers: { Authorization: `Bearer ${token}` } }
).then(r => r.json())
)
);
// Combine quarterly results
return combineAnalytics(results);
}