How to manage meta tags in Laravel and improve SEO.

Pavel Buchnev
Apr 1 · 4 min read

Hello world, everyone!
I have a lot of experience in Laravel. There are landing pages, blogs, shops, News portals, and many other sites. And the main problem of developing these sites was SEO. I hated this abbreviation.

Someday I decided to make a good package that can help me to solve all problems with SEO in Laravel. It was a very long way. There was the first version of my package (kodicms/laravel-assets) on and It was about 72k times downloaded, but I didn’t like it. It had a lot of problems, with tests, codebase, but the main problem was documentation. And I’ve decided to develop a new better version of the tool for managing meta tags, styles, scripts, OpenGraph, Twitter cards, e.t.c. with super documentation, by using TDD.

And finally let me introduce my new package butschster/meta-tags for managing meta tags and other tags in Laravel, that can help you save 90% of the time.

What is Laravel meta tags manager?

- Standard SEO
- Facebook OpenGraph
- Twitter Card
- Links to CSS files
- Links to JS files
- Tools for webmasters
- Extensions
- Good documentation

Now lets jump to the interesting part on how we can use this package in your laravel applications. At first you have to run the following command to include this package via Composer;

composer require butschster/meta-tags

Once the package is installed you need to register the service provider. Just run artisan command

php artisan meta-tags:install

Once that is done you can setup default application meta in config/meta_tags.php config.

* Meta title section
'title' => [
'default' => env('APP_NAME'),
'separator' => '-',
'max_length' => 255,

* Meta description section
'description' => [
'default' => null,
'max_length' => 255,

* Meta keywords section
'keywords' => [
'default' => null,
'max_length' => 255

'charset' => 'utf-8',
'robots' => null,
'viewport' => Viewport::RESPONSIVE,
'csrf_token' => true,

Once configuration is complete you can then add the below at the meta area of the main layout you want to include meta tags;

<html lang="en">

Now you can manage meta in your controllers like this:

use Butschster\Head\Facades\Meta;

class HomeController extends Controller {
public function index()
$news = News::paginate();
Meta::prependTitle('Home page')
->addMeta('robots', ['content' => 'noindex']);

That’s it!

But it’s only the beginning!

You can do things like this

Meta::addScript('bootstrap.js', '')
->addStyle('bootstrap.css', '');


Or… What about this?

You can group your meta tags, links, script into packages with names and set dependencies.

// Service providerPackageManager::create('jquery', function($package) {
PackageManager::create('bootstrap', function($package) {
->addScript('bootstrap.js', '')
->addStyle('bootstrap.css', '');

And include them into your layout via config

* Default packages
* Packages, that should be included everywhere
'packages' => [

Or via controller


bootstrap package will automatically resolve all dependencies and will include all of them before including itself


Scripts have to be in footer! You say: “Dude, what should I do, I want to place my scripts in footer”

No problem! :) Use custom placements!

By default all scripts use the footer placement, but you can change it! All other meta tags use head placement.

// Layout
// Controller
Meta::addScript('calendar.js', '', [], 'head')
Meta::addScript('calendar.js', '', [], 'my_custom_awesome_place')


At first you can create any meta tags and links. It’s very simple.

Meta::addMeta('author', [
'content' => 'butschster',
// <meta name="author" content="butschster">
Meta::addLink('apple-touch-icon-precomposed', [
'href' => '',
'id' => 'id:213'
// <link rel="apple-touch-icon-precomposed" href="" id="id:213" />

Most of meta tags packages don’t support extensions, but in this package you can use Laravel Macroable trait.

// Service provider
Meta::macro('registerSeoMetaTagsForPage', function (\App\Page $page) {

// Controller
use Butschster\Head\Facades\Meta;

class PageController extends Controller {

public function show(\App\Page $page)

Or you can your own class, that should implement interface \Butschster\Head\Contracts\MetaTags\Entities\TagInterface

use \Butschster\Head\Contracts\MetaTags\Entities\TagInterface;class FacebookPixelTag implements TagInterface {

public function __construct(string $id)

public function placement(): string
return 'footer'

public function toHtml()
return '<script type="text/javascript">...</script>'

Meta::addTag('facebook.pixel', new FacebookPixelTag('42b3h23-34234'));
// <script type="text/javascript">...</script>

More API and examples here


Recently my friend has asked a question: What can I add multiply favicons? Something like this:

<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/favicon-64x64.png" sizes="64x64" />
<!--[if IE gt 6]>
<link rel="icon" type="image/png" href="/favicon-ie.png" />

I said YES. let’s Ross it!

use Butschster\Head\MetaTags\Entities\Favicon;
use Butschster\Head\MetaTags\Entities\ConditionalComment;
PackageManager::create('favicons', function($package) {
$sizes = ['16x16', '32x32', '64x64'];
foreach ($sizes as $) {
$package->addTag('f.'.$size, new Favicon('/favicon-'.$size.'.png', [
'sizes' => $size
$package->addTag('', new ConditionalComment(
new Favicon('/favicon-ie.png'), 'IE gt 6'

I conclusion I have to say, this approach allows developers to use flexible meta tags, create reusable packages, and share them with you friends.

It took me some time to come up with this solution and i hope you like it.


P.S. What about JavaScript variables?

use \Butschster\Head\MetaTags\Entities\JavascriptVariables;

$variables = new JavascriptVariables([
'string' => 'Hello world',
'number' => 4815162342,
'bool' => true,
'nullable' => null

// you can put new variable
$variables->put('array', ['jquery', 'vuejs']);

Meta::addTag('variables', $variables);
// <script>
// window.array = ["jquery","vuejs"];
// window.string = 'Hello world';
// window.number = 4815162342;
// window.bool = true;
// window.nullable = null;
// </script>

Pavel Buchnev

Written by

Full Stack Developer