?>

How to get Google Calendar events in the search results

Have you ever seen those event listings in the search results and wondered how you can get them? Do you organize events, either online or offline that you want to give extra exposure? Do you want to get more clicks, more visitors, more business by easily promoting your events?

Take a look at what we were able to do for our LocalSpark client Urban Air Trampoline Park. When you search for events in their city, their events show up in the search results:

Overland Park events SERP

 

Their event listings also show up on branded search terms:

 

Want to know how I did it? Read on for step-by-step instructions.

FREE implementation: Google to the rescue!

Depending on the platform you’re using there are a number of solutions. In case you’re using WordPress there are many plugins (both free and paid) to choose from, in order to get events in the search results. In most cases, you’ll have to pay for solutions which connect to Google Calendar.

How about a FREE solution, using Google’s own platform to generate the required code to import in your website to show the events from one or more Google Calendars?

To get Google Calendar events in the search results, follow these steps:

  1. Create (or assign) a Google Calendar, dedicated to your online events list.
  2. Open Google Script Editor and copy/paste the code from the bottom of this blog post.
  3. Run the Google Apps Script and grant the required privileges
  4. Get the public URL of your Calendar Script
  5. Import the content from the URL from the desired page(s) of your site and output it at the right place in the PHP code of the template within your CMS

Check out the video below to see how you can accomplish this for yourself, or follow the instructions underneath the video (HINT: watch the video fullscreen to see more detail):

 

This might sound more difficult than it actually is. Don’t worry, let me take you through the steps, one step at a time.

Prerequisite: From here on, you need a Google account…

 

Step 1: Create a dedicated Google Calendar

Steps to create a new Google Calendar:

  1. Login to your Google account and go to https://calendar.google.com
  2. Click the little triangle next to “My calendars” in the left sidebar
  3. Click “Create new calendar”
  4. Give the calendar a name, set the correct location and timezone
  5. Click “Create calendar” button at the bottom when done
  6. Add one or more (dummy) events to the calendar so you’re able to test it

Step 2: Create and modify the script

To copy the script, surf to https://script.google.com and perform these steps:

  1. Assign a name to your project
  2. Select and remove all code
  3. Copy the Calendar Events Google Apps Script (below) to the clipboard and paste it in the editor
  4. Get the calendar ID (see below) and paste it in place of the ‘#####’ (5 hash tags / pound signs)

To get the Calendar ID or ID’s, do the following:

  1. In Google Calendar, click the wheel on the right and select “Settings”
  2. Click on the top menu on “Calendars”
  3. Select the calendar you just created
  4. Copy the ID to the clipboard
Get Google Calendar ID

Step 3: Grant the required privileges to the script

Your script can not be used, until you:

  1. Save the script by clicking on the little disk
  2. Select “doGet” in the “Select Function” dropdown box
  3. Click the “Play”-button
  4. Select “Continue” in the popup window, titled “Authorization required”
  5. When the next window pops up, asking to “Manage your calendars”, click “Allow”

Congratulations, you’re almost there…

Step 4: Get the public URL of the script

Once you’ve granted the correct authorization and made sure the script doesn’t return an error, follow these steps:

  1. Click “Publish” and select “Deploy as web app”
  2. Give an initial description
  3. Leave your Google ID under “Execute the app as:”
  4. Under “Who has access to the app:”, select “Anyone, even anonymous”
  5. Click on “Deploy”

You’re then shown a window with the “Current web app URL”. Copy it to the clipboard and paste it in a new browser window. If you’ve performed all steps correctly, you’ll see the events code, which you can embed in the source of your PHP template(s).

Step 5: Get the events in your PHP code

In order to get the events embedded in the source code of your HTML-code, you’ll most likely need to modify the PHP template(s) of your CMS.

Since WordPress is the most widely used CMS, I only focus on WordPress from here on. But for any PHP-based CMS, the solution will be quite comparable..

Once you have the events listed on your screen in the previous step, create a custom field named “eventlisturl” in the page you want to have the events listed in the search results. Copy/paste the URL from your browser into this custom field.

NOTE: Make sure that you DO NOT USE the “Current web app URL” shown in the Google Script Editor, as this will NOT WORK!

Then in the template of your theme, add the following PHP code (typically in footer.php, just before </body>):

if ( ($eventlisturl = get_post_meta( $post->ID, 'eventlisturl', true ) )) {
$eventlistoutput = file_get_contents( $eventlisturl );

$search = array( "$location", "$url" );
$replace = array( get_the_title(), "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
$eventlistoutput = str_replace( $search, $replace, $eventlistoutput );
echo $eventlistoutput;
}

This piece of PHP code assumes the following:

  • The custom field “eventlisturl” is set to the URL that you see when you view the script in your browser in step 6 above.
  • “$location” will be substituted by the HTML title of your page
  • “$url” will be set to the URL of the current page, so the event listing will link to the page containing the code

While any location in the code will be fine, I advise to place the code in the footer, just before the closing “</body>” tag.

Further customizations

It is also possible to customize the Location and URL fields by adding a bit of additional content to the event description in Google Calendar:

  • Add a line with e.g. “name: Whitespark HQ” (without the quotes) to have the location automatically set to “Whitespark HQ”
  • Add a line with ONLY a URL, e.g. “http://www.whitespark.ca/special-event” (without the quotes, but WITH http://) to link to the actual event page

Google Apps Script for Step 2:

function doGet() {

  var calIds = [ 
    "#####" // ID(s) of 1 or more Google Calendars
  ];

  var total = '';
  for ( var cal = 0; cal < calIds.length; cal++ ) {
    total = total + getEventsJSON( calIds[cal] );
  }

  return ContentService.createTextOutput().append(total);
}


function getEventsJSON( id ) {
  var now = new Date();
  var oneYearFromNow = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 365); // 1 Year in advance

  var output = '<script type="application/ld+json">\n';

  var events = CalendarApp.getCalendarById(id).getEvents(now, oneYearFromNow, {search: '*'});

  if ( events.length > 1 ) {
    output += '[';
  }

  Logger.log('Number of events: ' + events.length + ' in calendar "' + id + '"' );

  for (var i=0 ; i < events.length && i < 7 ;i++) {

    output += '{\n"@context": "http://schema.org",\n"@type": "Event",\n';
    
    var title  = events[i].getTitle();

    var starttime = events[i].getStartTime();
    var tz    = CalendarApp.getDefaultCalendar().getTimeZone();
    var start = Utilities.formatDate(starttime, tz, "yyyy-MM-dd HH:mm");

    var endtime = events[i].getEndTime();
    var end = Utilities.formatDate(endtime, tz, "yyyy-MM-dd HH:mm");

    var descr  = events[i].getDescription();
    var sameas = '';
    var name   = '';
    
    if ( (name = descr.match(/name: (.*)/i)) == null ) {
      name = '$location';
    } else {
      descr = descr.replace( name[0], '');
      name = name[1];
    }
    
    if ( (sameas = descr.match(/https?:[^\s]+/)) == null ) {
      sameas = '$url';
    } else {
      descr = descr.replace( sameas[0], '');
    }

    // Strip any trailing whitespace
    descr = descr.replace( /[\s]+$/g, '');

    var loc    = events[i].getLocation();

    output += '"name": "' + title + '",\n';
    output += '"startDate": "' + start + '",\n';
    output += '"endDate": "' + end + '",\n';
    output += '"location": {\n"@type": "Place",\n"name": "' + name + '",\n"address": "' + loc + '",\n"sameAs": "' + sameas + '"\n},\n';

    output += '"description": "' + descr + '"\n';
    output += '}';
   
    if ( events.length > 1 && i < Math.min((events.length-1), 6) ) {
      output += ',\n';
    }
  }
  
  if ( events.length > 1 ) {
      output += ']\n';
  }
  
  output += '</script>\n';

  return output;
}

Conclusion

There you have it. Follow the instructions above to get your events listed in the search results.

I hope this solution is useful for you. If you have any comments or questions, feel free to post them below and I’ll do my best to reply to them.

AUTHOR

Eduard de Boer

Eduard started with hand-coding websites in 1993 and became immersed in SEO, reputation management and content marketing in the years thereafter. After almost two decades Eduard is still following his passion: consulting and helping companies to profile themselves better. Eduard is also a certified Google Maps Business Photographer.

Follow Me on Twitter
  • Very useful tip, have put it in my tweet queue, will post it to my followers today. @HSchendera

  • Thank you, Harald. Glad you like it!

  • Thanks for the super useful articIe. Is there an all javascript solution for situations where one’s cms isn’t php based?

  • So complicated; you’d think they’d make it a little bit simpler.

  • Thanks for sharing, Eduard! This is excellent actionable advice. I’m going to give it a try today!

    Thanks,
    Kevin

  • Is this a working Jquery driven solution. It seems that this works (although I’m sure it could be optimized)

    the following code replaces step 5 above.

    the url inside the $(‘#loader’).load(‘your url goes here’); is the calendar’s unique url as stated in step 4.

    Google’s structured data testing tool doesn’t see the code, but if you inspect the page in chrome or firefox you can see the json-ld code right before the closing body tag. Google has claimed that it can crawl content that is loaded via ajax, so I’m wondering if this will work…

    You can see a test version at : http://learnerdesign.com/json-ld-test.html

  • Rob

    Dude!

    Timely for sure.

    and Eduard… ask Darren about gravatar.

    and Kevin (other commenter), excellent domain name

  • @Noah: when Google Structured Data Testing Tool isn’t seeing the events, they won’t get indexed.

    @Wesley: I tried to make it as easy to follow as possible. If anything is unclear, feel free to ask.

    @Kevin: thanks! Did it work for you?

    @Rob: Thanks for pointing the Gravatar issue out to me. I do have my whitespark.ca address associated with it, but for one reason or the other, it doesn’t show my photo… (Have now used my primary address, though 😉

  • Thanks for sharing this articIe! Very useful!

  • NYC Insider

    This is brilliant. Thank you so much for taking the time to outline all the steps (even for dummies like me). I’m close, but keep getting this error, “TypeError: Cannot call method “getEvents” of null. (line 22, file “Code”, project “NYC Calendar”)”. It then highlights this code:

    var events = CalendarApp.getCalendarById(id).getEvents(now, oneYearFromNow, {search: ‘*’});

    Any thoughts? I put in the correct ID where the hashtags were…what am I missing?

    Again, thank you so much.

  • William Jones

    Did not work for me what am I doing wrong?

    • hi William,

      This is a bit vague, so I don’t know what could be the issue. If you want you can contact me to see whether I can help you out.

      Regards, Eduard.

  • Noah T. Kaufman, MD

    I AM HAVING THE SAME EXACT PROBLEM. Tried to troubleshoot to no avail. Wish I could get this to work!

    Thanks for the info though!

  • Same Issue As Well;
    TypeError: Cannot call method “getEvents” of null. (line 22, file “Code”)

    var events = CalendarApp.getCalendarById(id).getEvents(now, oneYearFromNow, {search: ‘*’});

  • Hi Shanti, this solution is typically tailored to WordPress, as it’s by far the most use CMS on the planet.

    I don’t have experience with Wix, sorry. So I can’t say anything valid about that. Would have to look into it, to find out.

  • Hi NYC Insider,

    I would have to see the exact code you’re using. Feel free to reach out to me and I will see whether I can solve it for you.

    – Eduard.

  • Brandon Hughes

    Hello,

    Thank you for taking the time to post all of this information, as I run an events directory I am keen to implement.
    I have been getting this error however (I see some others have also)
    Cannot call method “getEvents” of null. (line 22, file “Code”)

    Any ideas on how to fix this?
    Thanks!

  • kamal gulati

    HI, the script that generates the events from Google calendar, only outputs 7 events .
    sorry not I’m not much of script editor, I followed the blog instructions and is working well.. thanks 4 that
    but it only generates 7 events , see my script –> (I am using the EXACT script from the blog page)

    https://script.google.com/macros/s/AKfycbxPlRbojKEjLwX-mn1ISYdVE6phpo3EBkmilhxK9l-xQlEnEHJs/exec

    I thought changing this line –> for (var i=0 ; i < events.length && i < 7 ;i++) to <21 for no. events 21 ??
    does not seem to work …

    • Hi Kamal,

      I choose for 7, as Google is only showing a maximum of 3 events in the SERPs. So, having a few more ready for Google would most likely cover the time between two visits of Googlebot, I found out.

      So, why would you like to have 21? It would only mean overkill in the HTML source and a potential waste of bandwidth.

      – Eduard.

      • kamal gulati

        thanks for the reply Eduard, We are a nightclub and we have events that people might want to purchase tickets for at least 2-3 months in advance, which is why I want events displayed in Google search that far ahead. typically we post 2 months of events on our website /FB etc…. which is why I want calendar events with at least 21 events etc…. but you are saying is that Google index won’t display that many calendar events anyways ??

      • kamal gulati

        ok I changed it to 21 , is working now
        thanks

  • Jonathan Chappell

    Did everything correctly and got the Schema data displaying in a browser, however when I went to add the data to the head of my page using:

    $calendarthing = file_get_contents(‘https://script.googleusercontent.com/macros/echo?user_content_key=blahdeblahetc123456789dummykey’);
    echo $calendarthing;

    and uploaded the page to a server I got the Google login page (One account. All of Google. Sign in to continue to Google Drive.) I got this even if I was viewing with the same Google acount as I had used to create the script.

    I DID select the correct settings for access anyone even anonymous

    This pretty well makes your script unuseable – do you have an update, fix or workaround?

  • Jonathan Chappell

    Further to my last, this will display the schema in the head of a web page that is .php
    If using Selerdeck or Actinic use a php block

    $eventlisturl =’https://script.googleusercontent.gobblydegookblahblahdummycode’;

    $eventlistoutput = file_get_contents( $eventlisturl );

    echo $eventlistoutput;

  • Jonathan Chappell

    Further to my last again I used a different calendar and am back to the code displaying the goole login page! Please help?

    • Hi Jonathan,

      I think we’d need to get on a Skype call, so you can share your screen. Because trying to troubleshoot through these comments here, seems a bit too cumbersome.

      I’ve sent you my details per mail.

      • Jonathan Chappell

        Hi Eduard. Thank you very much for coming back. I unticked the ‘make calendar public’ box and saved then ticked it again, saved again then generated the code and it seems to be ok! I will let you know if further problems.

        Thank you again.

        Best wishes

        Jonathan

  • Jasmine Lightfoot

    Hi,
    I’m trying to do this for my website which is html/ css so cannot use the php code. Could you let me know if there’s a way that I can adapt this step for html?