I'm using SharePoint 2007 and I would like to add the JS code for Google Analytics into the master page. I think a Delegate Control is the way to go, as we already have a Delegate Control in the Head section of the master page.

However, in this case there is a requirement to enable and disable the code per site, so would this still be the best approach?

I have put following code in .ascx file and writing in body tag instead of head tag.

protected override void Render(HtmlTextWriter writer) {
            if (SPContext.Current != null) {
                SPFile file = SPContext.Current.File;
                if (file.Item != null) {
                    if (file.Item.Fields.ContainsField(KeywordKey) &&
                      file.Item[KeywordKey] != null &&
                      file.Item[KeywordKey].ToString() != string.Empty) {
                        writer.Write(string.Format(@"<META name=""keywords"" content=""{0}"">", file.Item[KeywordKey].ToString()));
                     if (file.Item.Fields.ContainsField(DescriptionKey) &&
                      file.Item[DescriptionKey] != null &&
                      file.Item[DescriptionKey].ToString() != string.Empty) {
                        writer.Write(string.Format(@"<META name=""description"" content=""{0}"">", file.Item[DescriptionKey].ToString()));


i would like to write meta keywords on head section instead of body tags.

Thanks Ronak

Here's the Elements.xml

<?xml version="1.0" encoding="utf-8" ?> 
<Elements xmlns="schemas.microsoft.com/sharepoint/">; 
<!-- Use a sequence number lower than default of 100, so the custom control gets loaded before SharePoint controls --> 
<Control Id="AdditionalPageHead" Sequence="50" ControlSrc="~/_ControlTemplates/PhilaGov/MetaTagsKeyWords.ascx" /> 

Here's the Head section of Master Page

<HEAD runat="server">
<META Name="GENERATOR" Content="Microsoft SharePoint">
<META Name="progid" Content="SharePoint.WebPartPage.Document">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<META HTTP-EQUIV="Expires" content="0">
<SharePoint:RobotsMetaTag runat="server"/>
<Title ID=onetidTitle><asp:ContentPlaceHolder id=PlaceHolderPageTitle runat="server"/></Title>
<SharePoint:CssLink runat="server"/>
<SharePoint:Theme runat="server"/>
<SharePoint:ScriptLink language="javascript" name="core.js" Defer="true" runat="server"/>
<SharePoint:CustomJSUrl runat="server"/>
<SharePoint:SoapDiscoveryLink runat="server"/>
<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server"/>
<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>

UPDATE: Example page layout:

<%@ Page language="C#"   Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,Microsoft.SharePoint.Publishing,Version=,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceholderID="PlaceHolderAdditionalPageHead" runat="server">
    <PublishingWebControls:editmodepanel runat="server" id="editmodestyles">
            <!-- Styles for edit mode only-->
            <SharePointWebControls:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/zz2_editMode.css %>" runat="server"/>
    <SharePointWebControls:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/rca.css %>" runat="server"/>
    <PublishingWebControls:editmodepanel runat="server" id="displaymodejs" PageDisplayMode="Display">
            <!-- JavaScript for to remove OverViewbox if its empty-->
            <script type="text/javascript" language="javascript">
                    $(document).ready(function () { 
                          $(".overviewBox>div").filter(function (index) { return $(this).children().length < 1; }).parent().remove();
<asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server">
                <SharePointWebControls:FieldValue id="PageTitle" FieldName="Title" runat="server"/>
<asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
                <div class="widget breadcrumb">
                  <asp:SiteMapPath runat="server" id="SiteMapPath1" SkipLinkText="" SiteMapProvider="CurrentNavSiteMapProviderNoEncode"></asp:SiteMapPath>  
             <div class="widget pageTitle">
                    <SharePointWebControls:FieldValue id="HomePageTitleInTitleArea" FieldName="Title" runat="server"/></h1>
             <div class="grid_15 colRight">
                 <div class="widget overviewBox">
                      <PublishingWebControls:RichHtmlField FieldName="OverViewContent1" runat="server" 
                 <div class="widget WebPartEdit">
                      <PublishingWebControls:RichHtmlField FieldName="PublishingPageContent1" runat="server" 
                 <div class="widget overviewBox">
                      <PublishingWebControls:RichHtmlField FieldName="OverViewContent2" runat="server" 

                 <div class="widget WebPartEdit">
                      <PublishingWebControls:RichHtmlField FieldName="PublishingPageContent2" runat="server" 

                 <WebPartPages:WebPartZone runat="server" Title="BottomZone" ID="BottomZone"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
                 <PublishingWebControls:editmodepanel runat="server" id="editmodepanel1">
                    <!-- Add field controls here to bind custom metadata viewable and editable in edit mode only.-->
                    <SharePointWebControls:NoteField FieldName="MetaKeywords" runat="server"></SharePointWebControls:NoteField>
                    <SharePointWebControls:NoteField FieldName="MetaDescription" runat="server"></SharePointWebControls:NoteField>

             <div class="grid_5 colLeft">
                  <WebPartPages:WebPartZone runat="server" Title="LeftZone" ID="LeftZone"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>

  • Your last edit, is it a separate question?
    – James Love
    Commented Feb 3, 2012 at 20:08
  • Nope James its same question also i would like render js too in head section with MetaKeywords and Description but somehow its writing to Body section ? should i put my code in CreateChildControls method instead.
    – Ronak
    Commented Feb 3, 2012 at 20:12
  • If you put it in CreateChildControls nothing will be rendered as you're overriding the method the web part uses to render the controls. I would add the javascript lines in the same method you've pasted above. If you add the ASCX to the AdditionalPageHead control, it should go in the head tag.
    – James Love
    Commented Feb 3, 2012 at 20:22
  • True james i commented code for render events and doing CreatechildControls method and yes i am replacing AdditionalPageHead Delegate Control but dont know something weird is going on.
    – Ronak
    Commented Feb 3, 2012 at 20:25
  • Please post the code in your elements.xml for the delegate control feature.
    – James Love
    Commented Feb 3, 2012 at 20:28

3 Answers 3


Here's a complete example of a working ASCX SharePoint DelegateControl. It adds the required Google Analytics stuff plus any meta keywords you define.

First, the feature.xml:

  Title="Adds Google Analytics Counter (requires a Google Analytics ID)"
  Description="Activates feature for Google Analytics Web counter"
      <ElementManifest Location="elementManifest.xml"/>

Second, the elementManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Control Id="AdditionalPageHead" ControlSrc="~/_controltemplates/GoogleAnalytics.ascx"></Control>

Third, the GoogleAnalytics.ascx:

<%@ Control Language="C#" compilationMode="Always" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.WebControls" %>
    string keywords = "keyword-1,keyword-2";
    string idString = "UA-1234567-8";
    string requestProtocol = "http://www.";

        if (keywords != "")
            // Add keywords meta tag
            Response.Write("\n\n<meta name=\"keywords\" content=\"" + keywords + "\" />\n");

            // Write debug output, use Microsoft "DebugView" locally on the server to watch the output 
            Trace.WriteLine("meta keywords: " + keywords);

        if (idString != "")
            // Check if HTTPS (SSL) is used to request this page
            if (Request.IsSecureConnection)
                // Set appropriate SSL url
                requestProtocol = "https://ssl.";

            // Add async script load to page head
            Response.Write("<script type=\"text/javascript\">var _gaq = _gaq || [];_gaq.push(['_setAccount', '" + idString + "']);_gaq.push(['_trackPageview']);_gaq.push(['_trackPageLoadTime']);(function() {var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;ga.src = '" + requestProtocol + "google-analytics.com/ga.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);})();</script>");
    catch (Exception ex)
        Trace.WriteLine("Exception: " + ex.ToString());

You need to replace the keywords and idString variables with values of your choice and also create a valid feature id to pop into Feature Id="INSERTYOURGUIDHERE".

Also note the line starting with Trace.WriteLine. It shows how a simple tracing can be implemented and watched using the Microsoft DebugView (http://technet.microsoft.com/en-us/sysinternals/bb896647) utility.

You can use just a simple text editor (I prefer the free and open source Notepad++) and the Codeplex WSPBuilder to wrap it into a WSP and you're ready to deploy.

Once done, activate the feature on each SharePoint Website (SPWeb) of your choice and you're all set.

  • Thanks Sig is it ok to use Inline code in .ascx meaning do i need to tell sharepoint is it safe to use inline code ?
    – Ronak
    Commented Feb 6, 2012 at 14:32
  • Thanks Sig your code works but problem is it not writing to head section but body.Thanks
    – Ronak
    Commented Feb 6, 2012 at 16:02
  • Check your masterpage. It should have only one AdditionalPageHead inside the HEAD section.
    – Sig Weber
    Commented Feb 6, 2012 at 16:41
  • Thanks Sig it has only one AdditionalPageHead but still its pushing in Body section no matter what master page i use.Thanks
    – Ronak
    Commented Feb 6, 2012 at 17:38
  • 1
    Guys, we have a chat site for elaborate discussions like this. Comments are not for this kind of conversations. Commented Feb 7, 2012 at 19:50

You can develop a Delegate Control for the Head Section, by creating a SharePoint feature. That SharePoint feature can be enabled and disabled according to the Sites.

File -> New Project -> SharePoint Empty Project.

Add New Class and change its base class to System.Web.UI.WebControls.WebControl

Override required methods like OnLoad,CreateChildControls or Render.

Add New Module with Elements.xml and add the below tag. Ensure that the Safe property is set to true

<Control Id="AdditionalPageHead"  Sequence="100" ControlClass="addedclassFullName" ControlAssembly="$SharePoint.Project.AssemblyFullName$"  ></Control>

Instead of adding a class we can use an UserControl and refer it in ControlSrc property of Control tag in place of ControlClass and ControlAssembly.

Finally, deploy the feature.

Here is good tutorial

Here some best practices for using delegate controls in 2007

  • Thanks Styler for your reply i did that but somehow its not working.i create feature to replace AdditionalPageHead Delegate control in master page with .ascx which register js in code behind but its not working.
    – Ronak
    Commented Feb 3, 2012 at 16:50
  • Delegate Controls can be frustrating as when they don't load they don't do anything, not even log anything. Just keep trying different cases of _CONTROLTEMPLATES in the feature element, have your ASCX spit some Literal text out to see if the codebehind is failing for some reason... This method does work because I use it, but sometimes takes a bit of loving to get to work.
    – James Love
    Commented Feb 3, 2012 at 17:46
  • I agree with James but I have update some steps for you to see if you could find some missing links in your code... Commented Feb 3, 2012 at 23:43

Thanks Guys for Your Help and suggestion now its working.I reset master Page and all check to reset all sites and subsites to reset to masterpage settings and its working.

Thanks Ronak

  • Thanks for letting me know I'm not nuts ;) I've just finished testing on a MOSS 2007 virtual machine and couldn't reproduce your issue using a publishing site, so I suspected a masterpage issue. Would you mind marking one of the two answers as your preferred answer?
    – Sig Weber
    Commented Feb 7, 2012 at 10:32
  • @Sig i will do it today still there are some weird issue is going on doing more testing on it...will let you guys know wats going on ....Thanks for help
    – Ronak
    Commented Feb 7, 2012 at 13:41
  • Alright Guys Now i know wats going on first thing there is no problem with master page and it also work fine with out of Box PageLayouts but it does not like PageLayout that i have created in SPD 2007.I have Content type with two site columns named MetaKeywords and MetaDescription that content authors can modify and i have created PageLayouts based on this content types.i have no idea whats Problem going on.please advise Thanks
    – Ronak
    Commented Feb 7, 2012 at 14:35
  • Can you post the sourcecode of such a page layout? I suspect SPD is messing it up (wouldn't be the first time, you know).
    – Sig Weber
    Commented Feb 7, 2012 at 15:46
  • @sig i did but formatting looks bad though i don't know how to put code in here in nice format....Thanks again for looking into this...
    – Ronak
    Commented Feb 7, 2012 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.