npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ng-tweets

v1.0.0

Published

Get a tweet stream clientside without an auth token. Works by scraping the official twitter widget.

Readme

Angular Tweets

Get a tweet stream clientside without exposing a private auth token, and without any serverside code.

The stream will be provided to you via an ordinary $http promise object.

How does it work?

Twitter has a tight lock on its API. You can't access any API data without a token. However there is a back door, the official Twitter widget which returns HTML.

This module works by scraping the official twitter widget and parsing the result into JSON.

The official twitter widget makes a JSONP call to an API. It does this using a public widget id which allows access to the tweet stream from a single pre-chosen user.

This API call returns a JSON object full of HTML which the widget normally displays in an iframe.

This service pulls that stream, extracts the HTML and reverse engineers it back into a JSON object which can be saved in scope.

Once the tweet stream is in scope you can do what you like with it.

Can I get a demo?

You can find a working plunkr here.

http://plnkr.co/edit/gLkDBn?p=preview

Kudos

Kudos to Jason Mayes for the idea http://www.jasonmayes.com/projects/twitterApi/

Usage

Acquiring a widget ID

First go here https://twitter.com/settings/widgets/new and create a new widget. Configure the widget to your liking. The data from the widget will be used to compose the response. Inspect the generated widget code and grab the public widget ID. You will need this to configure the service.

You will not need an API key, secret, etc, etc.

Using the service

Inject "ngTweets" into your app. The module provides a service called tweets. Call tweets.get and pass it your widget ID. You will get back an $http promise object which you can interact with in the usual way.

The controller:

angular.module('app', ['ngTweets'])
  .controller('twitterController', function($scope, tweets) {
    tweets.get({
      widgetId: '123456'
    }).success(function(data) {
      $scope.feed = data;
    });
  });

The view:

<body ng-controller="twitterController">
  <ul>
    <li ng-repeat='tweet in feed.tweets'>
      <pre>{{tweet | json }}</pre>
    </li>
  </ul>
</body>

Sample response

You will receive an object containing a header, and an array with a maximum of 20 tweets.

{
  headers: {
    "status": 200,
    "xPolling": 30,
    "time": 1431449793
  },
  tweets: [
    {
      "retweet": false,
      "id": "598156558984290304",
      "html": "<a href=\"https://twitter.com/kasiakatie\" class=\"PrettyLink profile customisable h-card\" dir=\"ltr\" data-scribe=\"element:mention\">@<b class=\"p-nickname\">kasiakatie</b></a> An unusual choice for breakfast, but we're glad that you enjoyed it :-)",
      "text": "@kasiakatie An unusual choice for breakfast, but we're glad that you enjoyed it :-)",
      "author": {
        "url": "https://twitter.com/higgidy",
        "avatar": "https://pbs.twimg.com/profile_images/378800000697698644/d09c29afa453ce0e224266efda526210_normal.jpeg",
        "fullName": "Higgidy",
        "nickName": "@higgidy"
      },
      "updated": "53m",
      "permalink": "https://twitter.com/higgidy/status/598156558984290304"
    },
    {
      "retweet": false,
      "id": "598130095232913408",
      "html": "Mmm, good choice <a href=\"https://twitter.com/Mmelulu\" class=\"PrettyLink profile customisable h-card\" dir=\"ltr\" data-scribe=\"element:mention\">@<b class=\"p-nickname\">Mmelulu</b></a>",
      "text": "Mmm, good choice @Mmelulu",
      "author": {
        "url": "https://twitter.com/higgidy",
        "avatar": "https://pbs.twimg.com/profile_images/378800000697698644/d09c29afa453ce0e224266efda526210_normal.jpeg",
        "fullName": "Higgidy",
        "nickName": "@higgidy"
      },
      "updated": "2h",
      "permalink": "https://twitter.com/higgidy/status/598130095232913408"
    },
    {
      "retweet": false,
      "id": "598125208021635072",
      "html": "During the <a href=\"https://twitter.com/artistshouses\" class=\"PrettyLink profile customisable h-card\" dir=\"ltr\" data-scribe=\"element:mention\">@<b class=\"p-nickname\">artistshouses</b></a> you can wander into random people's houses (including Abby &amp; Cedar's) and not get told off <a href=\"http://t.co/mSA5CV480n\" class=\"PrettyLink link media customisable\" data-pre-embedded=\"true\" dir=\"ltr\" data-scribe=\"\">pic.twitter.com/mSA5CV480n</a>",
      "text": "During the @artistshouses you can wander into random people's houses (including Abby & Cedar's) and not get told off pic.twitter.com/mSA5CV480n",
      "author": {
        "url": "https://twitter.com/higgidy",
        "avatar": "https://pbs.twimg.com/profile_images/378800000697698644/d09c29afa453ce0e224266efda526210_normal.jpeg",
        "fullName": "Higgidy",
        "nickName": "@higgidy"
      },
      "updated": "2h",
      "permalink": "https://twitter.com/higgidy/status/598125208021635072"
    }
  ]
}

Error handling

The header object contains information about any errors that occurred upstream. The header status would normally be 200. Anything else is an error.

Downstream errors are currently not handled. Please feel free to submit a patch for this.

Contributing

Please feel free to contribute by forking this repository and submitting a pull request. Contributors will be credited in this Readme.

About me

I'm an Angular developer and trainer working out of Brighton, England. You can find Angular lessons on my website here http://www.nicholasjohnson.com

Browser compatibility

IE9+ only please. It should work everywhere Angular 1.3.1 works.

Likelihood of failure

Because this service works by scraping HTML, it will fail if the HTML changes. This could happen at any time without warning. Caution is advised.

Warranty

This plugin is a dirty low down (albeit functional) hack. My assumption is that this hack is likely to remain available as long as older browsers require JSONP to access the API. However I can make no guarantees on this. This is not an official twitter API, there is no uptime guarantee, Twitter can turn it off at any time.

Caution is advised. Use at your discretion. I take no responsibility for any problems of any kind you may encounter, technical, legal, spiritual, military, etc.

License

MIT license, use it as you see fit. I'm not going to sue you.