In this post I share some code with you that I used to create a custom section and dashboard in Umbraco 8.

The code comes from a discontinued package I made a while back. I might do a mini tutorial series on this one day. Credit to Kevin Jump who created the Do Stuff With Umbraco repository that I think I learned most of this from.

Anyway, here's what you need.

A dashboard.html file stored here "/App_Plugins/GAEvents/dashboards/dashboard.html"

<div ng-controller="GAEventsDashboardController as vm">

    <umb-load-indicator ng-if="vm.loading">

    <div ng-if="!vm.loading">
        <div class="alert alert-warning" ng-if="vm.licenseStatus == 1">
            You need a license before you can use this in production <strong><a href="" target="_blank">more info</a></strong>

        <div class="alert alert-danger" ng-if="vm.licenseStatus == 3">
            Your license is invalid <strong><a href="" target="_blank">more info</a></strong>

        <h1>GA Events</h1>
        <p>This package allows you to track events on your website, such as downloading PDFs, clicking on links, submitting forms etc.
            It helps you learn how your users are using your website. The data is sent straight to your Google Analytics account.</p>
        <p>Using this package you can create almost any event you wish, by hooking into events such as click, and submit and targeting specific elements for these events.</p>

        <h2>Getting set up</h2>
            <p>For this package to work you need to use Google's analytics.js</p>
            <p>In the below code snippet, replace the UA-XXXXXXXXX-1 with your analytics id from Google Analtyics.</p>
            <p>Make sure you put this code after the opening body tag in your master template or on all of the pages you wish to track events on.</p>
&lt;!-- Google Analytics --&gt;
&nbsp; (function(i,s,o,g,r,a,m){i[&#39;GoogleAnalyticsObject&#39;]=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

  ga(&#39;create&#39;, &#39;UA-XXXXXXXXX-1&#39;, &#39;auto&#39;);
&lt;!-- End Google Analytics --&gt;
            <p>On the front end of your site, include the gaEvents script which comes with this package:</p>
&lt;script src=&quot;/scripts/gaEvents.js&quot;&gt;&lt;/script&gt;</pre>
            <p>Now all you need to do is create some events and you will start seeing them show up in the Events section of your Google Analytics account.</p>
            <button class="btn btn-primary btn-large" ng-click="vm.createBlank()">
                <i class="icon-edit"></i>
                Create New Event

dashboardController.js file stored here "/App_Plugins/GAEvents/dashboards/dashboardController.js"

(function () {
    'use strict';

    function dashboardController($scope, $location, navigationService, gaEventsDataResource) {
        var vm = this;
        vm.loading = true;


        // functions
        vm.createBlank = createBlank;

        function createBlank() {
            $location.path('/gaEventsSection/GAEventsTree/edit/-1').search('create', 'true');

        function init() {
            vm.licenseStatus = 0;

            gaEventsDataResource.getLicense().then(function (response) {
                vm.licenseStatus = response.Status;
                vm.loading = false;


        .controller('GAEventsDashboardController', dashboardController);

Dashboard class to register the dashboard. GAEventsDashboard.cs

using System;
using Umbraco.Core.Composing;
using Umbraco.Core.Dashboards;

namespace GAEvents.Core.Dashboards
    public class GAEventsDashboard : IDashboard
        public string Alias => "GAEventsDashboard";

        public string[] Sections => new[]

        public string View => "/App_Plugins/GAEvents/dashboards/dashboard.html";

        public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();

Section class GAEventsSection.cs

using Umbraco.Core.Models.Sections;

namespace GAEvents.Core.Sections
    /// <summary>
    ///  Custom Section Interface, see GAEventsSectionComposer for how
    ///  this is registered in umbraco, GAEventsSectionComponent ads the 
    ///  section to the admin group so it appears by default.
    /// </summary>
    public class GAEventsSection : ISection
        /// <summary>
        ///  Alias for the section
        /// </summary>
        /// <remarks>
        ///  It makes sense to make this a constant (you don't have to)
        ///  because you end up refrencing it in things like tree's and 
        ///  dashboards.
        /// </remarks>
        public const string SectionAlias = "gaEventsSection";

        #region ISection Interface 

        /// <summary>
        ///  Alias of section, used in urls, trees etc
        /// </summary>
        public string Alias => SectionAlias;

        /// <summary>
        ///  name of the section - this isn't what the user sees
        ///  they see a value from the lang file
        /// </summary>
        public string Name => "GA Events";


Composer and Component to regsiter the section GAEventsSectionComposer

using GAEvents.Core.Sections;
using System;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Web;

namespace GAEvents.Core.Composing
    class GAEventsSectionComposer : IUserComposer
        public void Compose(Composition composition)
            // register the section 

            // register the component that adds the section
            // to the admin group 

    /// <summary>
    ///  Umbraco Component (runs at startup) 
    /// </summary>
    /// <remarks>This doesn't run unless it's registered in the Composer</remarks>
    public class GAEventsSectionComponent : IComponent
        private readonly IUserService userService;
        private readonly IKeyValueService keyValueService;
        private readonly IProfilingLogger logger;

        private const string setupKey = "gaEventsSection_installed";

        public GAEventsSectionComponent(
            IUserService userService,
            IKeyValueService keyValueService,
            IProfilingLogger logger)
            this.userService = userService;
            this.keyValueService = keyValueService;
            this.logger = logger;

        public void Initialize()
            // a quick version of only run once. 
            // for a more complete set of methods see Migrations samples
            var installed = keyValueService.GetValue(setupKey);
            if (installed == null || installed != "installed")
                AddSection("admin", GAEventsSection.SectionAlias);
                keyValueService.SetValue(setupKey, "installed");

        /// <summary>
        ///  add the given section to the given user group 
        /// </summary>
        /// <remarks>
        ///  if umbraco throws an exception here, we capture it
        ///  because if we don't umbraco won't startup and that
        ///  might be a bad thing :( 
        /// </remarks>
        /// <param name="groupAlias"></param>
        /// <param name="sectionAlias"></param>
        private void AddSection(string groupAlias, string sectionAlias)
            using (logger.DebugDuration<GAEventsSectionComponent>($"Adding Section {sectionAlias} to {groupAlias}"))
                var group = userService.GetUserGroupByAlias(groupAlias);
                if (group != null)
                    if (!group.AllowedSections.Contains(sectionAlias))

                            logger.Info<GAEventsSectionComponent>($"Section {sectionAlias} added to {groupAlias} group");
                        catch (Exception ex)
                            logger.Warn<GAEventsSectionComponent>("Error adding section {0} to group {1} [{2}]",
                                sectionAlias, groupAlias, ex.Message);

        public void Terminate()
            // umbraco is shutting down -

I hope this helps you out one day.

Paul Seal

Umbraco MVP and .NET Web Developer from Derby (UK) who specialises in building Content Management System (CMS) websites using MVC with Umbraco as a framework. Paul is passionate about web development and programming as a whole. Apart from when he's with his wife and son, if he's not writing code, he's thinking about it or listening to a podcast about it.

Proudly sponsored by


  • Moriyama build, support and deploy Umbraco, Azure and ASP.NET websites and applications.

  • CI/CD service for Windows, Linux and macOS
  • Build, test, deploy your apps faster, on any platform.

  • Custom stickers for startups, artists and brands.
  • Bespoke easy-apply, removable, custom brand stickers printed in the UK.

  • is the easy error logging and uptime monitoring service for .NET.
  • Take back control of your errors with support for all .NET web and logging frameworks.
uSync Complete

  • uSync.Complete gives you all the uSync packages, allowing you to completely control how your Umbraco settings, content and media is stored, transferred and managed across all your Umbraco Installations.

  • More than a theme for Umbraco CMS, take full control of your content and design with a feature-rich, award-nominated & content editor focused website platform.

  • Affordable, Geo-Redundant, Umbraco hosting which gives back to the community by sponsoring an Umbraco Open Source Developer with each hosting package sold.