We've seen projects where simply configuring Open Graph and convenient share buttons increased CTR from social networks by 4 times. Over 5 years, we've implemented such integrations for 30+ projects — from blogs to marketplaces. In this article, we'll cover the full cycle: from meta tags to dynamic images and buttons with UTM tags.
A common mistake among developers is considering share buttons a secondary detail. In reality, without correct OG tags, Facebook and Telegram pull previews randomly, and without UTM tags, you can't track channel effectiveness. The result is lost traffic.
Why Open Graph Meta Tags Are Critical for Sharing
Without OG tags, social networks take the title and image from HTML — often inappropriate. Proper markup creates an attractive block: title, description, image 1200×630. This directly affects CTR — according to our data, an increase of up to 50% depending on preview design. According to the Open Graph documentation, the minimum requirements are: og:title, og:description, og:image, og:url. For articles — og:type=article and article:published_time.
// Blade: meta tags for an article
<meta property="og:title" content="{{ $article->title }}">
<meta property="og:description" content="{{ $article->excerpt }}">
<meta property="og:image" content="{{ $article->og_image_url }}">
<meta property="og:image:width" content="1200">
<meta property="og:image:height"content="630">
<meta property="og:url" content="{{ url()->current() }}">
<meta property="og:type" content="article">
<meta property="og:locale" content="ru_RU">
<meta property="article:published_time" content="{{ $article->published_at->toIso8601String() }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ $article->title }}">
<meta name="twitter:description" content="{{ $article->excerpt }}">
<meta name="twitter:image" content="{{ $article->og_image_url }}">
The image must be at least 1200×630 and no heavier than 5 MB. Optimal size is up to 300 KB, JPEG with progressive loading (improves LCP by 15–20%).
How to Generate Dynamic OG Images?
A static image for all pages is bad practice. Each article or product should have a unique preview. We use dynamic generation: a template (background + logo) with the title overlaid. In Laravel, this is done via Intervention Image. Code:
// Dynamic OG image generation 1200×630
Route::get('/og/{article}', function (Article $article) {
$image = \Intervention\Image\Facades\Image::make(public_path('og-template.png'));
$image->text($article->title, 600, 280, function ($font) {
$font->file(public_path('fonts/Inter-Bold.ttf'));
$font->size(48);
$font->color('#1a1a1a');
$font->align('center');
$font->valign('middle');
});
return response($image->encode('jpg', 90))->header('Content-Type', 'image/jpeg')
->header('Cache-Control', 'public, max-age=86400');
})->name('og.image');
Caching for a day reduces load. According to our measurements, dynamic OG images increase CTR by 30–50% compared to static ones. This is also confirmed by A/B tests: conversion to clicks from VK grows by an average of 40%.
Comparison of Native API and Custom Links
| Feature | Native Web Share API | Custom Links |
|---|---|---|
| Support | Chrome Mobile, Safari Mobile, Samsung Internet | All browsers |
| UTM control | No way to add | Full control |
| Required code | One navigator.share call | Separate link per network |
| Desktop fallback | None in Firefox and Safari | Works everywhere |
The native API is 2 times faster to implement than custom links, but requires a fallback. Custom links provide flexibility: you can add UTM tags and track clicks. We combine both approaches: if the browser supports navigator.share, we show a native button; otherwise, individual social network icons. This hybrid scheme covers 95% of users.
React implementation:
const SHARE_URLS = {
telegram: (url: string, title: string) =>
`https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
vk: (url: string, title: string) =>
`https://vk.com/share.php?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`,
twitter: (url: string, title: string) =>
`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
whatsapp: (url: string, title: string) =>
`https://wa.me/?text=${encodeURIComponent(title + ' ' + url)}`,
};
function ShareButtons({ url, title }: { url: string; title: string }) {
const share = (network: keyof typeof SHARE_URLS) => {
window.open(SHARE_URLS[network](url, title), '_blank', 'width=600,height=400,noopener');
};
const copyLink = async () => {
await navigator.clipboard.writeText(url);
// show toast
};
const nativeShare = async () => {
if (navigator.share) {
await navigator.share({ title, url });
}
};
return (
<div className="share-buttons" role="group" aria-label="Share">
{navigator.share && (
<button onClick={nativeShare} aria-label="Share">↗ Share</button>
)}
<button onClick={() => share('telegram')} aria-label="Share on Telegram">TG</button>
<button onClick={() => share('vk')} aria-label="Share on VK">VK</button>
<button onClick={copyLink} aria-label="Copy link">🔗</button>
</div>
);
}
Add UTM parameters: utm_source={network}&utm_medium=social&utm_campaign=share. This will show in analytics which channel brought traffic. Recommended parameters:
| Parameter | Example value |
|---|---|
| utm_source | vk, telegram, twitter |
| utm_medium | social |
| utm_campaign | share |
| utm_content | post-{id} |
Our Work Process
- Analysis — we determine content types, collect preview requirements.
- Design — create OG image template, button design.
- Implementation — integrate meta tags, image generation, sharing component.
- Testing — check previews in social networks, button functionality on different devices.
- Deployment — roll out to production, set up monitoring.
Common mistakes
- Incorrect OG image size — Facebook crops it if proportions aren't 1.91:1.
- Missing Twitter Card — preview doesn't show in Twitter.
- Copy link button doesn't work — forgot to check
navigator.clipboardsupport. - Native API doesn't fall back on desktop — always leave a fallback.
Web Share API is supported in Chrome Mobile, Safari Mobile, Samsung Internet, but missing in desktop versions of Firefox and Safari. Consider this when choosing your strategy.
Timeframes and Cost
Timeframes: from 1 to 3 days depending on complexity (only meta tags — 0.5 days, with image generation and buttons — 2–3 days). Cost is calculated individually — contact us for a project estimate.
We guarantee results: you'll get working share buttons with beautiful previews that actually increase traffic from social networks. Contact us to discuss details.







