Card-Specific Social Sharing: The ?art Parameter Story
2025-10-04
Card-Specific Social Sharing: The ?art Parameter Story
Have you ever wanted to share a specific printing of a Magic card - maybe a gorgeous Secret Lair alternate art or a vintage frame version - only to have the social media preview show the wrong artwork? We had this exact problem, and today I want to share how we solved it with a simple, elegant query parameter.
The Problem
Our card pages support multiple printings of the same card. For example, "Homeward Path" has been printed in:
- Commander 2013 (original art)
- Commander Legends
- Secret Lair Drop (alternate art)
- Judge Gift Cards
- And more...
When users clicked on different prints in our gallery, they could view each one. But when they tried to share their favorite art variant, Discord/Twitter/Facebook always showed the default printing in the preview card.
User expectation: "I want to share this Secret Lair version!"
Actual result: Generic preview with Commander 2013 art
Why Social Media Previews Matter
Social media platforms like Discord, Twitter, and Facebook use Open Graph and Twitter Card metadata to generate rich previews when someone shares a link. These previews include:
- Title (the card name)
- Description (card text)
- Image (card artwork)
- URL (the link being shared)
The image is especially important for Magic cards because:
- Players often share cards based on artwork
- Alternate arts are collectible and worth discussing
- Visual recognition is how players identify cards
When the wrong artwork appears, it breaks the sharing experience.
The Simple Solution: Query Parameters
We implemented art-specific sharing using URL query parameters:
Default (No Parameter)
https://takescake.com/cards/cb8ec264-8223-41f2-8f2c-37c918a573fa
Shows the first/default printing (usually the oldest or most recent).
Specific Art Variant
https://takescake.com/cards/cb8ec264-8223-41f2-8f2c-37c918a573fa?art=b23a6f7e-c0b8-4e85-9270-254bfb221ae0
Shows the specific print with ID b23a6f7e-c0b8-4e85-9270-254bfb221ae0
.
The ?art={card-id}
parameter tells the page which printing to feature in social previews.
How It Works
1. URL Structure
Magic cards have two types of IDs:
- Oracle ID: Identifies the card concept (e.g., "Homeward Path" as a game piece)
- Card ID: Identifies a specific printing (e.g., "Homeward Path from Secret Lair")
Our URLs use oracle IDs as the path:
/cards/{oracle-id}
The query parameter specifies the card ID:
?art={card-id}
This makes sense conceptually: "Show me Homeward Path (oracle), specifically the Secret Lair printing (card)."
2. Metadata Generation
When generating Open Graph and Twitter Card metadata, we check for the art
parameter:
export async function generateMetadata({
params,
searchParams
}: {
params: { oracle: string },
searchParams: { art?: string }
}): Promise<Metadata> {
// Get all printings for this oracle ID
const versions = listVersionsForOracle(all, params.oracle, 'released', 'desc', 'en');
// Default to first printing
let featuredCard = versions[0];
// If ?art={id} provided, use that specific printing
if (searchParams.art) {
const specificCard = versions.find(v => v.id === searchParams.art);
if (specificCard) {
featuredCard = specificCard;
}
}
// Use the featured card's image for social previews
const cardImage = getCardImagePath(featuredCard.id, 'large');
return {
openGraph: {
url: searchParams.art
? `${baseUrl}?art=${searchParams.art}`
: baseUrl,
images: [{ url: cardImage, ... }]
},
twitter: {
images: [cardImage]
}
};
}
The key insight: we only change which card image is used. The title and description stay the same because oracle text doesn't change between printings.
3. Automatic URL Updates
When users click different prints in the gallery, we automatically update the URL using JavaScript:
useEffect(() => {
if (typeof window === 'undefined' || !featuredId) return;
const url = new URL(window.location.href);
const currentArt = url.searchParams.get('art');
// Update URL if featured print changed
if (featuredId !== initialFeaturedId) {
if (currentArt !== featuredId) {
url.searchParams.set('art', featuredId);
window.history.replaceState({}, '', url.toString());
}
} else {
// Remove art param if back to default
if (currentArt) {
url.searchParams.delete('art');
window.history.replaceState({}, '', url.toString());
}
}
}, [featuredId, initialFeaturedId]);
We use replaceState
(not pushState
) so the URL updates don't create browser history entries. Users can still use the back button normally.
4. Image Path Resolution
The tricky part was making sure the correct image was used. Our card images are stored as:
public/cards/{card-id}-normal.jpg
Each individual print has its own image file. The original implementation was looking up images by oracle ID, which only works for the default print.
The fix:
// Construct direct path to specific print's image
const directLocalPath = `/cards/${featuredCard.id}-normal.jpg`;
const directLocalAbsolute = `${siteUrl}${directLocalPath}`;
// Fallback to manifest lookup if needed
const manifestImg = getCardImagePath(manifest, featuredCard.oracle_id, 'large');
// Priority: direct path > manifest > Scryfall remote
const finalImage = directLocalAbsolute || manifestImg || scryfallFallback;
Now we construct the image path directly from the card ID, ensuring we always get the right artwork.
User Experience Flow
Here's what happens when a user wants to share a specific print:
Step 1: Browse Prints
User visits a card page and sees multiple printings in the gallery.
Step 2: Select Favorite Art
User clicks on their favorite alternate art (e.g., Secret Lair version).
Step 3: URL Updates
The browser's address bar automatically updates to include ?art={card-id}
.
Step 4: Copy and Share
User copies the URL from the address bar.
Step 5: Preview Generated
When pasted into Discord/Twitter/Facebook, the social media platform:
- Fetches the URL
- Reads the Open Graph metadata
- Sees the specific card image for that print
- Displays the correct artwork in the preview!
Step 6: Others Click Through
When friends click the link, they see:
- The same featured print
- All other available prints in the gallery
- Can browse and share their own favorite
Why This Design is Good
1. Simple Implementation
No complex routing. No database changes. Just a query parameter check in metadata generation.
2. Backward Compatible
Old links without ?art=
parameter still work perfectly - they show the default print.
3. Shareable URLs
URLs are human-readable and can be copy-pasted, sent in messages, bookmarked, etc.
4. No Performance Cost
Parameter checking happens during SSR (server-side rendering) - zero client-side overhead.
5. SEO Friendly
Search engines see the canonical URL with the art parameter, improving indexing of popular alternate arts.
6. User Discoverable
Users don't need to be told about this feature - it just works when they click different prints.
Edge Cases Handled
Non-Existent Card IDs
If someone manually edits the URL with a fake card ID:
if (searchParams.art) {
const specificCard = versions.find(v => v.id === searchParams.art);
if (specificCard) {
featuredCard = specificCard;
}
// If not found, fall back to default (no error)
}
We silently fall back to the default print. No errors, no confusion.
Missing Images
If the local image file doesn't exist for a specific print:
const directLocalAbsolute = `${siteUrl}${directLocalPath}`;
const manifestImg = getCardImagePath(...);
const scryfallFallback = card.image_uris?.large;
const finalImage = directLocalAbsolute || manifestImg || scryfallFallback;
We have multiple fallback layers ending with Scryfall's remote images.
Social Media Cache
Discord and other platforms cache Open Graph metadata for 24 hours. If we change images, it might take a day for updates to show.
Solution: The ?art=
parameter creates a unique URL per print, so each gets its own cache entry.
Testing Social Media Previews
After implementing this feature, we tested using:
Discord
Paste URLs in any channel. Discord fetches and displays preview cards immediately.
Twitter Card Validator
https://cards-dev.twitter.com/validator
Enter the URL to see how Twitter will display it.
Facebook Debugger
https://developers.facebook.com/tools/debug/
Shows Open Graph metadata and preview rendering.
LinkedIn Post Inspector
https://www.linkedin.com/post-inspector/
Validates Open Graph tags and preview display.
All platforms now correctly show art-specific previews! 🎉
Real-World Examples
Example 1: Homeward Path Variants
Default Print (Commander 2013):
https://takescake.com/cards/cb8ec264-8223-41f2-8f2c-37c918a573fa
Secret Lair Drop:
https://takescake.com/cards/cb8ec264-8223-41f2-8f2c-37c918a573fa?art=b23a6f7e-c0b8-4e85-9270-254bfb221ae0
Example 2: Sol Ring Variations
With 50+ printings, Sol Ring is perfect for this feature:
Original Alpha:
https://takescake.com/cards/5effb651-f9e0-4c14-8192-bd0e132b8d5d?art=fd1b7c92-a11b-447a-bcef-03c7f5e8fd55
Kaladesh Inventions:
https://takescake.com/cards/5effb651-f9e0-4c14-8192-bd0e132b8d5d?art=895e7a6e-cd10-4a00-bfec-30e6330e193c
Each URL shows the exact printing in social previews.
Future Enhancements
We're considering additional improvements:
1. Share Buttons
Add explicit "Share this print" buttons with pre-filled social links:
<a href="https://twitter.com/intent/tweet?url={cardUrl}?art={cardId}">
Share on Twitter
</a>
2. Set Symbol Badges
Add visual indicators showing which set each print is from.
3. Print Comparison Mode
Side-by-side view of multiple arts with shareable comparison URLs.
4. Collector Numbers
Include collector number in the URL for even more specificity.
For now, the simple ?art=
parameter solves 99% of sharing needs.
Try It Yourself
Visit any card with multiple printings on takescake.com:
- Click different prints in the gallery
- Watch the URL update automatically
- Copy the URL and share it on Discord/Twitter
- See the correct artwork in the preview!
It's a small feature, but it makes sharing Magic cards feel natural and precise.
Technical Note: Implementation spans app/cards/[oracle]/page.tsx
(metadata generation) and components/CardPrintGallery.tsx
(URL sync). Zero performance impact, full backward compatibility.