DEV Community

Cover image for Crawl Vote: Helping groups on the move pick a next spot
Nick Holden
Nick Holden

Posted on

Crawl Vote: Helping groups on the move pick a next spot

What I built

Crawl Vote helps groups on the move pick a next spot. Whether they’re looking for poutine in Montreal or tacos in Tijuana, Crawl Vote will return some suggestions for everyone to vote on together.

Demo link

Link to code

GitHub logo nholden / crawl_vote

Helps groups on the move choose a next spot

Crawl Vote

Helps groups on the move choose a next spot


git clone git://
cd crawl_vote
brew install redis postgresql heroku
bundle install
cp .env.example .env
bundle exec rake db:reset

Getting started

Sign up for a Pusher Channels app at and a Yelp API key at and update .env.

Start these long-running processes in separate terminal windows:

heroku local

Crawl Vote should be accessible at http://localhost:3345 (or whichever port you specify in .env).


bundle exec rspec


Contributions are welcome from everyone! Feel free to make a pull request or use GitHub issues for help getting started, to report bugs, or to make feature requests.


This project was created by Nick Holden and is licensed under the terms of the MIT license.

How I built it

Crawl Vote uses Ruby on Rails on the back end Vue.js on the front end. I used Webpacker, which comes with a Vue integration, to compile and bundle my JavaScript, CSS, and images. I used Tailwind to quickly prototype my design without writing any CSS.

I used Pusher Channels in a couple ways. When a user first submits where they’re going and what they’re looking for, Crawl Vote creates a new “crawl”, gives it a unique name, and subscribes the user to a Pusher channel with that name. Then, the application kicks off a Sidekiq job to query Yelp’s Fusion API in the background. Once the job has fetched relevant businesses and persisted them to the PostgreSQL database, it triggers an event to the Pusher channel. When the user’s browser receives the event, a Vue component uses the Fetch API to make a request to grab all of the relevant data and display it on the screen.

Once the user has successfully created a crawl and invited some friends, Pusher Channels allow everyone to see the voting in real time without refreshing their browsers. When a user clicks the vote button next to a spot, it makes a request to the application that persists the vote and triggers an event to the Pusher channel. When all the users’ browsers receive the event, the Vue component makes another request to refresh the data on the screen.

Crawl Vote demo

I had never used Vue’s List Move Transitions before, but I was really impressed how, with very little CSS, Vue added silky smooth animations as spots moved up and down in the rankings. Magic! ✨

To identify users, Crawl Vote assigns each person a UUID and stores it in the user’s session. When a user first visits a crawl or refreshes the page, the applications identifies the user directly from the session and renders the data server side. When the user’s browser receives a Pusher event letting it know that it’s time to fetch more data, the UUID is sent along as a token in the authorization request header.

Crawl Vote is continuously deployed to Heroku by Travis CI and is served by Cloudflare. I’m using Rollbar for exception tracking and Papertrail for logging. The only thing I paid for was the domain name, which came from Namecheap.

What’s next

I’m happy with how things turned out for this MVP, but I have a whole bunch of things I’d love to try with more time. I’d like to increase test coverage, including at least one or two Rails system tests that click through my Vue components using Headless Chrome.

I’d also like to continue improving the UX/UI, including adding autocomplete to the form fields. The categories that Yelp’s autocomplete endpoint returns look like they could be useful for the “Find” field, and I’ve been happy working with Google’s Place Autocomplete in the past. The design overall could use a little sprucing up, and I think some thoughtful use of color could help the look and feel better reflect the spirit of the app.

Finally, it would be great to do some more tweaking with the parameters Crawl Vote sends along to Yelp’s API. There are a lot of options, and I’m not sure I’d want to expose too many to the user since the complexity could turn people away, but I’d love to do some optimizing to make sure Crawl Vote returns a great selection of spots for every query.

Top comments (9)

jrohatiner profile image

This is really nice. Clean code, good concept, its a real gem (get it? RoR people- lol)! I totally get your trajectory for features in the future and I like the way you left it open for that. Great work!

nholden profile image
Nick Holden

Thanks very much, JR! Since I wrote the post and brought in some real traffic, my todo list has continued to grow even more. Happy with how the MVP turned out, though!

maestromac profile image
Mac Siri

This is really really cool!

nholden profile image
Nick Holden

Thanks, Mac! 😁

ben profile image
Ben Halpern

Super polished. Really nice!

nholden profile image
Nick Holden

Thanks for the kind words, Ben!

figspville profile image
Salli Figler

I like it. Although it has characteristics of other apps, it is different and new. Do you have a specific target audience for this?

nholden profile image
Nick Holden

Thank you, Salli! Aside from "co-located groups of people," I didn't have a specific target audience in mind. I'd imagine it's more useful in more urban settings where the Yelp API will have more relevant results to return.

nholden profile image
Nick Holden

Thanks a bunch, Alex!