{"id":19491107,"url":"https://github.com/jublo/codebird-js","last_synced_at":"2026-03-08T16:32:38.695Z","repository":{"id":1549493,"uuid":"1919642","full_name":"jublo/codebird-js","owner":"jublo","description":"A Twitter library in JavaScript.","archived":false,"fork":false,"pushed_at":"2022-02-11T11:33:53.000Z","size":549,"stargazers_count":384,"open_issues_count":30,"forks_count":97,"subscribers_count":26,"default_branch":"develop","last_synced_at":"2025-03-29T12:11:13.549Z","etag":null,"topics":["codebird","codebird-js","cors-proxy","javascript","oauth","twitter-api","twitter-library"],"latest_commit_sha":null,"homepage":"https://www.jublo.net/projects/codebird/js","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"vrtadmin/clamav-devel","license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jublo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-06-19T15:18:40.000Z","updated_at":"2024-09-19T05:10:20.000Z","dependencies_parsed_at":"2022-08-16T13:45:15.292Z","dependency_job_id":null,"html_url":"https://github.com/jublo/codebird-js","commit_stats":null,"previous_names":["jublonet/codebird-js","mynetx/codebird-js"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jublo%2Fcodebird-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jublo%2Fcodebird-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jublo%2Fcodebird-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jublo%2Fcodebird-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jublo","download_url":"https://codeload.github.com/jublo/codebird-js/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339158,"owners_count":20923014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codebird","codebird-js","cors-proxy","javascript","oauth","twitter-api","twitter-library"],"created_at":"2024-11-10T21:15:46.850Z","updated_at":"2025-12-12T04:23:39.151Z","avatar_url":"https://github.com/jublo.png","language":"JavaScript","readme":"# codebird-js\n\n_A Twitter library in JavaScript._\n\nCopyright (C) 2010-2018 Jublo Limited \u003csupport@jublo.net\u003e\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\n[![Travis Status](https://img.shields.io/travis/jublonet/codebird-js/develop.svg)](https://travis-ci.org/jublonet/codebird-js/branches)\n\n## Including Codebird\n\nTo include Codebird in your code, add its scripts to your markup:\n\n```html\n\u003cscript type=\"text/javascript\" src=\"codebird.js\"\u003e\u003c/script\u003e\n\n\u003cscript type=\"text/javascript\"\u003e\nvar cb = new Codebird;\ncb.setConsumerKey(\"YOURKEY\", \"YOURSECRET\");\n\u003c/script\u003e\n```\n\nYou may also use a JavaScript module loader of your choice\n(such as [RequireJS](http://requirejs.org/) or the one bundled in Node.js)\nto load Codebird unobtrusively. In Node.js, loading Codebird looks like this:\n\n```javascript\nvar Codebird = require(\"codebird\");\n// or with leading \"./\", if the codebird.js file is in your main folder:\n// var Codebird = require(\"./codebird\");\n\nvar cb = new Codebird();\ncb.setConsumerKey(\"YOURKEY\", \"YOURSECRET\");\n```\n\n## Authentication\n\nTo authenticate your API requests on behalf of a certain Twitter user\n(following OAuth 1.0a), take a look at these steps:\n\n```html\n\u003cscript type=\"text/javascript\" src=\"codebird.js\"\u003e\u003c/script\u003e\n\n\u003cscript type=\"text/javascript\"\u003e\nvar cb = new Codebird;\ncb.setConsumerKey(\"YOURKEY\", \"YOURSECRET\");\n\u003c/script\u003e\n```\n\nYou may either set the OAuth token and secret, if you already have them:\n\n```javascript\ncb.setToken(\"YOURTOKEN\", \"YOURTOKENSECRET\");\n```\n\nOr you authenticate, like this:\n\n```javascript\n// gets a request token\ncb.__call(\"oauth_requestToken\", { oauth_callback: \"oob\" }, function(\n  reply,\n  rate,\n  err\n) {\n  if (err) {\n    console.log(\"error response or timeout exceeded\" + err.error);\n  }\n  if (reply) {\n    if (reply.errors \u0026\u0026 reply.errors[\"415\"]) {\n      // check your callback URL\n      console.log(reply.errors[\"415\"]);\n      return;\n    }\n\n    // stores the token\n    cb.setToken(reply.oauth_token, reply.oauth_token_secret);\n\n    // gets the authorize screen URL\n    cb.__call(\"oauth_authorize\", {}, function(auth_url) {\n      window.codebird_auth = window.open(auth_url);\n    });\n  }\n});\n```\n\n:warning: Codebird server calls do not always go through when\nbeing processed in a hyperlink onclick handler. Be sure to cancel\nthe default procedure before calling Codebird, like this (jQuery):\n\n```javascript\n$(function() {\n\n    $('#auth').click(function(e) {\n        e.preventDefault();\n\n        var cb = new Codebird;\n// ...\n```\n\nNow you need to add a PIN box to your website.\nAfter the user enters the PIN, complete the authentication:\n\n```javascript\ncb.__call(\n  \"oauth_accessToken\",\n  { oauth_verifier: document.getElementById(\"PINFIELD\").value },\n  function(reply, rate, err) {\n    if (err) {\n      console.log(\"error response or timeout exceeded\" + err.error);\n    }\n    if (reply) {\n      // store the authenticated token, which may be different from the request token (!)\n      cb.setToken(reply.oauth_token, reply.oauth_token_secret);\n    }\n\n    // if you need to persist the login after page reload,\n    // consider storing the token in a cookie or HTML5 local storage\n  }\n);\n```\n\n### Logging out\n\nIn case you want to log out the current user (to log in a different user without\ncreating a new Codebird object), just call the `logout()` method.\n\n```javascript\ncb.logout().then(() =\u003e {\n  // user is now logged out\n});\n```\n\nCodebird also supports calling the oauth/invalidate_token method directly:\n\n```\ncb.__call(\"oauth_invalidateToken\", {\n  access_key:        \"1234\",\n  access_key_secret: \"5678\"\n}).then(() =\u003e {\n  // tokens are now reset\n});\n```\n\n### Application-only auth\n\nSome API methods also support authenticating on a per-application level.\nThis is useful for getting data that are not directly related to a specific\nTwitter user, but generic to the Twitter ecosystem (such as `search/tweets`).\n\nTo obtain an app-only bearer token, call the appropriate API:\n\n```javascript\ncb.__call(\"oauth2_token\", {}, function(reply, err) {\n  var bearer_token;\n  if (err) {\n    console.log(\"error response or timeout exceeded\" + err.error);\n  }\n  if (reply) {\n    bearer_token = reply.access_token;\n  }\n});\n```\n\nI strongly recommend that you store the obtained bearer token in your database.\nThere is no need to re-obtain the token with each page load, as it becomes invalid\nonly when you call the `oauth2/invalidate_token` method.\n\nIf you already have your token, tell Codebird to use it:\n\n```javascript\ncb.setBearerToken(\"YOURBEARERTOKEN\");\n```\n\nIn this case, you don't need to set the consumer key and secret.\nFor sending an API request with app-only auth, see the ‘Usage examples’ section.\n\n### Authenticating using a callback URL, without PIN\n\n1. Before sending your user off to Twitter, you have to store the request token and its secret, for example in a cookie.\n2. In the callback URL, extract those values and assign them to the Codebird object.\n3. Extract the `oauth_verifier` field from the request URI.\n\nIn Javascript, try extracting the URL parameter like this:\n\n```javascript\nvar cb = new Codebird();\nvar current_url = location.toString();\nvar query = current_url.match(/\\?(.+)$/).split(\"\u0026amp;\");\nvar parameters = {};\nvar parameter;\n\ncb.setConsumerKey(\"STUFF\", \"HERE\");\n\nfor (var i = 0; i \u003c query.length; i++) {\n  parameter = query[i].split(\"=\");\n  if (parameter.length === 1) {\n    parameter[1] = \"\";\n  }\n  parameters[decodeURIComponent(parameter[0])] = decodeURIComponent(\n    parameter[1]\n  );\n}\n\n// check if oauth_verifier is set\nif (typeof parameters.oauth_verifier !== \"undefined\") {\n  // assign stored request token parameters to codebird here\n  // ...\n  cb.setToken(\n    stored_somewhere.oauth_token,\n    stored_somewhere.oauth_token_secret\n  );\n\n  cb.__call(\n    \"oauth_accessToken\",\n    {\n      oauth_verifier: parameters.oauth_verifier\n    },\n    function(reply, rate, err) {\n      if (err) {\n        console.log(\"error response or timeout exceeded\" + err.error);\n      }\n      if (reply) {\n        cb.setToken(reply.oauth_token, reply.oauth_token_secret);\n      }\n\n      // if you need to persist the login after page reload,\n      // consider storing the token in a cookie or HTML5 local storage\n    }\n  );\n}\n```\n\n## Usage examples\n\n:warning: _Because the Consumer Key and Token Secret are available in the code,\nit is important that you configure your app as read-only at Twitter,\nunless you are sure to know what you are doing._\n\nWhen you have an access token, calling the API is simple:\n\n```javascript\ncb.setToken(\"YOURTOKEN\", \"YOURTOKENSECRET\"); // see above\n\ncb.__call(\"statuses_homeTimeline\", {}, function(reply, rate, err) {\n  console.log(reply);\n  console.log(err);\n});\n```\n\nTweeting is as easy as this:\n\n```javascript\ncb.__call(\"statuses_update\", { status: \"Whohoo, I just tweeted!\" }, function(\n  reply,\n  rate,\n  err\n) {\n  // ...\n});\n```\n\n:warning: _Make sure to urlencode any parameter values that contain\nquery-reserved characters, like tweeting the `\u0026` sign:_\n\n```javascript\nvar params = \"status=\" + encodeURIComponent(\"Fish \u0026 chips\");\ncb.__call(\"statuses_update\", params, function(reply, rate, err) {\n  // ...\n});\n```\n\nIn most cases, giving all parameters in an array is easier,\nbecause no encoding is needed:\n\n```javascript\nvar params = {\n  status: \"Fish \u0026 chips\"\n};\ncb.__call(\"statuses_update\", params, function(reply, rate, err) {\n  // ...\n});\n```\n\n```javascript\nvar params = {\n  screen_name: \"jublonet\"\n};\ncb.__call(\"users_show\", params, function(reply, rate, err) {\n  // ...\n});\n```\n\n```javascript\nvar params = {\n  q: \"NYC\"\n};\ncb.__call(\"search_tweets\", params, function(reply) {\n  // ...\n});\n```\n\n### Uploading media to Twitter\n\nTweet media can be uploaded in a 2-step process, and the media have to be\nbase64-encoded. **First** you send each image to Twitter, like this:\n\n```javascript\nvar params = {\n    \"media_data\": \"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB+0lEQVR42mP8//8/Ay0BEwONwagFoxZQDljI0PP8x7/Z93/e+PxXmpMpXp5dh4+ZgYHh0bd/clxYnMuINaMtfvRLgp3RVZwVU+rkuz+eRz+//wXVxcrEkKnEceXTX0dRlhoNTmKDaOvzXwHHv6x9+gtN/M9/hpjTX+GmMzAw/P7HMOnOj+ff//35x/Ds+z9iLfjPwPDt7//QE1/Sz319/RNh3PkPf+58+Yup/t7Xf9p8zFKcTMRa4CLGCrFm1v2fSjs+pJ/7uuvl7w+//yO7HRkUq3GEyrCREMk+kqy2IiyH3/xhYGD48uf/rPs/Z93/yczIwM3CiFU9Hw5xnD4ouvTt4Tf0AP37n+HTb+w+UOBmIs2CICm2R9/+EZlqGRkYzIVYSLMgRIYtUYGdSAsMBFgUuJhIy2iMDAwt2pysjAwLHv78RcgnOcrs5BQVHEyMG579Imi6Nh9zrBxZFgixMW624pXnwldYcTAzLjDhZmUit7AzE2K54c7fp8eF1QhWRobFptwmgiwkF3b//jMwMjJ8+P3/zPs/yx/9Wvr412+MgBJlZ1xsyuOOrbAibMHH3/87b32fce/nR2ypnpuFMVGevU6TQ5SdqKKeEVez5cuf/7te/j727s+9L/++/v3PzcyowM1kIcTiLs7Kz8pIfNnOONouGrVg1AIGAJ6gvN4J6V9GAAAAAElFTkSuQmCC\"\n);\ncb.__call(\n    \"media_upload\",\n    params,\n    function (reply, rate, err) {\n        // you get a media id back:\n        console.log(reply.media_id_string);\n\n        // continue upload of 2nd image here, if any (just 1 image works, too!)\n    }\n);\n```\n\n**Second,** you attach the collected media ids for all images to your call\nto `statuses/update`, like this:\n\n```javascript\ncb.__call(\n    \"statuses_update\",\n    {\n        \"media_ids\": \"12345678901234567890,9876543210987654321\"\n        \"status\": \"Whohoo, I just tweeted two images!\"\n    },\n    function (reply, rate, err) {\n        // ...\n    }\n);\n```\n\nMore [documentation for uploading media](https://developer.twitter.com/en/docs/media/upload-media/overview) is available on the Twitter Developer site.\n\n### Requests with app-only auth\n\nTo send API requests without an access token for a user (app-only auth),\nadd another parameter to your method call, like this:\n\n```javascript\ncb.__call(\n  \"search_tweets\",\n  \"q=Twitter\",\n  function(reply) {\n    // ...\n  },\n  true // this parameter required\n);\n```\n\nBear in mind that not all API methods support application-only auth.\n\n## Mapping API methods to Codebird function calls\n\nAs you can see from the last example, there is a general way how Twitter’s API methods\nmap to Codebird function calls. The general rules are:\n\n1. For each slash in a Twitter API method, use an underscore in the Codebird function.\n\n   Example: `statuses/update` maps to `cb.__call(\"statuses_update\", ...)`.\n\n2. For each underscore in a Twitter API method, use camelCase in the Codebird function.\n\n   Example: `statuses/home_timeline` maps to `cb.__call(\"statuses_homeTimeline\", ...)`.\n\n3. For each parameter template in method, use UPPERCASE in the Codebird function.\n   Also don’t forget to include the parameter in your parameter list.\n\n   Examples:\n\n   - `statuses/show/:id` maps to `cb.__call(\"statuses_show_ID\", 'id=12345', ...)`.\n   - `users/profile_image/:screen_name` maps to\n     `cb.__call(\"users_profileImage_SCREEN_NAME\", \"screen_name=jublonet\", ...)`.\n\n## HTTP methods (GET, POST, DELETE etc.)\n\nNever care about which HTTP method (verb) to use when calling a Twitter API.\nCodebird is intelligent enough to find out on its own.\n\n## Response codes\n\nThe HTTP response code that the API gave is included in any return values.\nYou can find it within the return object’s `httpstatus` property.\n\n### Dealing with rate-limits\n\nBasically, Codebird leaves it up to you to handle Twitter’s rate limit.\nThe library returns the response HTTP status code, so you can detect rate limits.\n\nI suggest you to check if the `reply.httpstatus` property is `400`\nand check with the Twitter API to find out if you are currently being\nrate-limited.\nSee the [Rate Limiting FAQ](https://developer.twitter.com/en/docs/basics/rate-limiting)\nfor more information.\n\nIf you allow your callback function to accept a second parameter,\nyou will receive rate-limiting details in this parameter,\nif the Twitter API responds with rate-limiting HTTP headers.\n\n```javascript\ncb.__call(\"search_tweets\", \"q=Twitter\", function(reply, rate_limit_status) {\n  console.log(rate_limit_status);\n  // ...\n});\n```\n\n## API calls and the same-origin policy\n\nNormally, browsers only allow requests being sent to addresses that are on\nthe same base domain. This is a security feature called the “same-origin\npolicy.” However, this policy is in your way when you try to access the\n(remote) Twitter API domain and its methods.\n\n### Cross-domain requests\n\nWith Codebird, don’t worry about this. We automatically send cross-domain\nrequests using a secured proxy that sends back the required headers to the\nuser’s browser.\n\nThis CORS proxy is using an encrypted SSL connection.\n_We do not record data sent to or from the Twitter API.\nUsing Codebird’s CORS proxy is subject to the Acceptable use policy._\n\nIf your JavaScript environment is not restricted under the same-origin policy\n(for example in node.js), direct connections to the Twitter API are established\nautomatically, instead of contacting the CORS proxy.\n\nYou may also turn off the CORS compatibility manually like this:\n\n```javascript\ncb.setUseProxy(false);\n```\n\n### Support for Internet Explorer 7 to 9\n\nCross-domain requests work well in any browser except for\nInternet Explorer 7-9. Codebird cannot send POST requests in these browsers.\nFor IE7-9, Codebird works in limited operation mode:\n\n- Calls to GET methods work fine,\n- calling POST methods is impossible,\n- Application-only auth does not work.\n\n### Using your own proxy server\n\nThe source code of the CORS proxy is publicly available. If you want to,\nset up your own instance on your server. Afterwards, tell Codebird the\naddress:\n\n```javascript\ncb.setProxy(\"https://example.com/codebird-cors-proxy/\");\n```\n\nHeads up! Follow the notes in the [codebird-cors-proxy README](https://github.com/jublonet/codebird-cors-proxy/#readme) for details.\n\n## Using multiple Codebird instances\n\nBy default, each Codebird instance works on its own.\n\nIf you need to run requests to the Twitter API for multiple users at once,\nCodebird supports this automatically. Just create a new object:\n\n```javascript\nvar cb1 = new Codebird();\nvar cb2 = new Codebird();\n```\n\nPlease note that your OAuth consumer key and secret is shared within\nmultiple Codebird instances, while the OAuth request and access tokens with their\nsecrets are _not_ shared.\n\n## How Do I…?\n\n### …get user ID, screen name and more details about the current user?\n\nWhen the user returns from the authentication screen, you need to trade\nthe obtained request token for an access token, using the OAuth verifier.\nAs discussed in the section ‘Usage example,’ you use a call to\n`oauth/access_token` to do that.\n\nThe API reply to this method call tells you details about the user that just logged in.\nThese details contain the **user ID** and the **screen name.**\n\nTake a look at the returned data as follows:\n\n```javascript\n{\n    oauth_token: \"14648265-rPn8EJwfB**********************\",\n    oauth_token_secret: \"agvf3L3**************************\",\n    user_id: 14648265,\n    screen_name: \"jublonet\",\n    httpstatus: 200\n}\n```\n\nIf you need to get more details, such as the user’s latest tweet,\nyou should fetch the complete User Entity. The simplest way to get the\nuser entity of the currently authenticated user is to use the\n`account/verify_credentials` API method. In Codebird, it works like this:\n\n```javascript\ncb.__call(\"account_verifyCredentials\", {}, function(reply) {\n  console.log(reply);\n});\n```\n\nI suggest to cache the User Entity after obtaining it, as the\n`account/verify_credentials` method is rate-limited by 15 calls per 15 minutes.\n\n### …walk through cursored results?\n\nThe Twitter REST API utilizes a technique called ‘cursoring’ to paginate\nlarge result sets. Cursoring separates results into pages of no more than\n5000 results at a time, and provides a means to move backwards and\nforwards through these pages.\n\nHere is how you can walk through cursored results with Codebird.\n\n1. Get the first result set of a cursored method:\n\n```javascript\ncb.__call(\"followers_list\", {}, function(result1) {\n  // ...\n});\n```\n\n2. To navigate forth, take the `next_cursor_str`:\n\n```javascript\nvar nextCursor = result1.next_cursor_str;\n```\n\n3. If `nextCursor` is not 0, use this cursor to request the next result page:\n\n```javascript\nif (nextCursor \u003e 0) {\n  cb.__call(\"followers_list\", { cursor: nextCursor }, function(result2) {\n    // ...\n  });\n}\n```\n\nTo navigate back instead of forth, use the field `resultX.previous_cursor_str`\ninstead of `next_cursor_str`.\n\nIt might make sense to use the cursors in a loop. Watch out, though,\nnot to send more than the allowed number of requests to `followers/list`\nper rate-limit timeframe, or else you will hit your rate-limit.\n\n### …use xAuth with Codebird?\n\nCodebird supports xAuth just like every other authentication used at Twitter.\nRemember that your application needs to be whitelisted to be able to use xAuth.\n\nHere’s an example:\n\n```javascript\ncb.__call(\n  \"oauth_accessToken\",\n  {\n    x_auth_username: \"username\",\n    x_auth_password: \"4h3_p4$$w0rd\",\n    x_auth_mode: \"client_auth\"\n  },\n  function(reply) {\n    console.log(reply);\n    // ...\n  }\n);\n```\n\nIf everything went fine, you will get an object like this:\n\n```javascript\n{\n    \"oauth_token\": \"14648265-ABLfBFlE*********************************\",\n    \"oauth_token_secret\": \"9yTBY3pEfj*********************************\",\n    \"user_id\": \"14648265\",\n    \"screen_name\": \"jublonet\",\n    \"x_auth_expires\": \"0\",\n    \"httpstatus\": 200\n}\n```\n\nAre you getting a strange error message, an empty error, or status \"0\"?\nIf the user is enrolled in login verification, the server will return a\nHTTP 401 error with a custom body (that may be filtered by your browser).\n\nYou may check the browser web console for an error message.\n\nWhen this error occurs, advise the user to\n[generate a temporary password](https://twitter.com/settings/applications)\non twitter.com and use that to complete signing in to the application.\n\n### …access the Collections API?\n\nCollections are a type of timeline that you control and can be hand curated\nand/or programmed using an API.\n\nPay close attention to the differences in how collections are presented —\noften they will be decomposed, efficient objects with information about users,\nTweets, and timelines grouped, simplified, and stripped of unnecessary repetition.\n\nNever care about the OAuth signing specialities and the JSON POST body\nfor POST and PUT calls to these special APIs. Codebird takes off the work for you\nand will always send the correct Content-Type automatically.\n\nFind out more about the [Collections API](https://developer.twitter.com/en/docs/tweets/curate-a-collection/overview/about_collections) in the Twitter API docs.\nMore information on the [Direct Messages API](https://developer.twitter.com/en/docs/direct-messages/api-features) and the [Account Activity API](https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/overview) is available there as well.\n\nHere’s a sample for adding a Tweet using the Collections API:\n\n```javascript\ncb.__call(\n  \"collections_entries_curate\",\n  {\n    id: \"custom-672852634622144512\",\n    changes: [{ op: \"add\", tweet_id: \"672727928262828032\" }]\n  },\n  function(reply, rate) {\n    document.body.innerText = JSON.stringify(reply);\n  }\n);\n```\n\n### …use promises instead of callback functions?\n\nHave you ever heard of the [Pyramid of Doom](http://calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web/)?\nIt’s when code progresses more to the right because of excessive nesting\nthan it progresses from top to bottom.\n\nBecause of the asynchronous requests, Codebird will use callbacks that you provide.\nThey are called when the result from the Twitter API has arrived.\nHowever, to streamline code, there is a sleeker concept for this: Promises.\n\nThere are several popular libraries that support promises.\nCodebird will auto-detect and use any of the following:\n\n- jQuery Deferred\n- Q\n- RSVP\n- when\n\nHere’s a usage sample for promises:\n\n```javascript\ncb.__call(\"statuses_update\", { status: \"Whohoo, I just tweeted!\" }).then(\n  function(data) {\n    var reply = data.reply,\n      rate = data.rate;\n    // ...\n  },\n  function(err) {\n    // ...\n  }\n);\n```\n\nSince the app-only flag is the fourth parameter for `__call`,\nyou’ll have to provide a callback stub nonetheless even with promises:\n\n```javascript\ncb.__call(\n  \"search_tweets\",\n  { q: \"#PHP7\" },\n  null, // no callback needed, we have the promise\n  true // app-only auth\n).then(\n  function(data) {\n    var reply = data.reply,\n      rate = data.rate;\n    // ...\n  },\n  function(err) {\n    // ...\n  }\n);\n```\n\n**Tips:**\n\n- If you provide **both** (callback and promise.then),\n  Codebird will first call the callback, then resolve the promise.\n\n- If the request fails due to any errors, Codebird will reject the promise.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjublo%2Fcodebird-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjublo%2Fcodebird-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjublo%2Fcodebird-js/lists"}