Using the Meetup API in Client-Side Applications

This post is more than 2 years old.

This isn't new, but was something I discovered a few weeks ago and I'm finally making the time to blog about it. I've used the Meetup API in the past with ColdFusion and for the most part, it just works, but like many APIs today it requires authenticated calls to get data. Unfortunately, even a simple search against public data also required an authenticated call. This means using the API in a purely client-side application won't be secure because your code will contain your secret keys.

Or so you would think. It isn't obvious at first (or wasn't to me), but the API actually supports "Key signatures". What this means is that you can design an API call, like, find me the meetups around area X that use the word "kitten" in the description and Meetup will give you a "signed" version of the URL to use in your application. Now here's the killer part. That URL is 100% safe to use because it will only do precisely what you told it to: Search for groups around area X with kitten in the name. Even better, this "lock" on the URL does not apply to anything related to paging or JSON/P callbacks. So outside of not being terribly obvious (at least in my opinion), this is a killer feature of the API and one worth considering for your next application.

In order to test this, you will need to have an account with Meetup and be logged in. Then simply go to the API Console and begin testing. Here is a screen shot of that in action:

shot1

You'll want to use the console to get your API calls down exactly as you want them and once you're satisfied, just copy and paste that URL into your code. I went ahead and whipped up a quick demo that performs a search for Ionic meetups around the world. Here's the code - and to be clear - this was quick and dirty, not nice.

function fetchGroups(url, cb, data) {
	if(!data) data = [];
	
	$.ajax({
		
		dataType:'jsonp',
		method:'get',
		url:url,
		success:function(result) {
			console.log('back with ' + result.data.length +' results');
			console.dir(result);
			//add to data
			data.push.apply(data, result.data);
			if(result.meta.next_link) {
				var nextUrl = result.meta.next_link;
				fetchGroups(nextUrl, cb, data);
			} else {
				cb(data);	
			}
		}
	});	
	
}

$(document).ready(function() {
	
	var $results = $("#results");

	$results.html("<p>Finding meetups with Ionic in the description.</p>");

	fetchGroups("https://api.meetup.com/find/groups?&photo-host=public&page=50&text=ionic&sig_id=2109318&radius=global&order=newest&sig=ad335a79ccce2b1bb65b27fe10ea6836305e5533&callback=?", function(res) {
		console.log("totally done");
		console.dir(res);	

		var s = "";
		for(var i=0;i<res.length; i++) {
			var group = res[i];
			s += "<h2>"+(i+1)+" <a href='"+group.link+"'>"+group.name+"</a></h2>";
			if(group.group_photo && group.group_photo.thumb_link) {
				s += "<img src=\"" + group.group_photo.thumb_link + "\" align=\"left\">";
			}
			s += "<p>Location: "+group.city + ", " + group.state + " " + group.country + "</p><br clear=\"left\">";
		}
		$results.html(s);
		
		
	});
		
});

I created a simple recursive function, fetchGroups, that lets me pass the initial signed URL in and deal with aggregating multiple pages of results. When finished, it then calls a callback function with the results. I should have used Promises perhaps, but, I was being lazy. The results are rendered out somewhat simply, but that could be improved of course.

You can view a live demo of this here: https://static.raymondcamden.com/demos/2015/nov/20/. Let me know what you think!

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Teliov Croby posted on 11/24/2015 at 1:09 PM

Hi Ray, cool stuff here. As to the using authenticated calls in client side API calls, one solution as prescribed here (http://alexbilbie.com/2014/... is to have a proxy guy that has your API credentials and makes the actual requests to the API and returns the data to your application.

Comment 2 (In reply to #1) by Raymond Camden posted on 11/24/2015 at 2:05 PM

Well, yes, but that's kinda well known, right? Most folks will proxy to a server, so I didn't even mention it as it is the 'typical' way of handling stuff like this. Meetup letting us 'sign' a call is a great workaround.

Comment 3 by Tom O posted on 9/29/2016 at 6:39 PM

Hi Ray, I just want the next event date , nothing else. Im designing a site that has a large red 'meetup' styled link button that just dsiplays the date of the next meetup.

I've played with
https://secure.meetup.com/m...
and I'm unclear how to get the next event date from the JSON package returned.

Any suggestions would be appreciated,
Thanks for your time
Tom

Comment 4 (In reply to #3) by Tom O posted on 9/29/2016 at 6:48 PM

having just posted I've just realised, use the time in milliseconds and convert to a date... doh !
Thanks anyhow ;)

Comment 5 (In reply to #4) by Raymond Camden posted on 9/29/2016 at 6:49 PM

Glad you got it. :)

Comment 6 by Cat posted on 2/27/2017 at 6:57 AM

Did you get the "No 'Access-Control-Allow-Origin' header" error? I'm getting that and don't know how to get around it. Does that mean that I have to use OAuth?

Comment 7 (In reply to #6) by Raymond Camden posted on 2/27/2017 at 4:05 PM

I'm using JSONP for my call.

Comment 8 by Nikola posted on 9/3/2018 at 1:27 PM

Hello Raymond,
this work good, but when I put url for searching upcoming events instead of groups it doesn't work. Something in fetchGroups function is not right. Do you know what need to be changed to work? Aside name, of course.
Its old post and I hope you remember.
Thanks anyways.

Comment 9 (In reply to #8) by Raymond Camden posted on 9/4/2018 at 1:24 PM

How doesn't it work? What do you see in your browser's console?

Comment 10 (In reply to #9) by Nikola posted on 9/4/2018 at 9:48 PM

I fix problem. To write a list of events instead groups return result is in different format. There is cities and events. So I replace
data.push.apply(data, result.data);
with
data.push.apply(data, result.data.events);
and work good.
Thanks anyway.