{"id":13509524,"url":"https://github.com/parroty/extwitter","last_synced_at":"2025-10-21T18:47:02.134Z","repository":{"id":14723765,"uuid":"17444436","full_name":"parroty/extwitter","owner":"parroty","description":"Twitter client library for elixir. ","archived":false,"fork":false,"pushed_at":"2024-12-25T04:40:00.000Z","size":589,"stargazers_count":409,"open_issues_count":22,"forks_count":127,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-28T22:20:49.918Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parroty.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-03-05T15:07:08.000Z","updated_at":"2025-01-31T22:18:22.000Z","dependencies_parsed_at":"2024-01-05T21:59:43.373Z","dependency_job_id":"648b3800-b0f7-449a-8f9f-4ffa6cd2b29f","html_url":"https://github.com/parroty/extwitter","commit_stats":null,"previous_names":[],"tags_count":55,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parroty%2Fextwitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parroty%2Fextwitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parroty%2Fextwitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parroty%2Fextwitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parroty","download_url":"https://codeload.github.com/parroty/extwitter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246324059,"owners_count":20759072,"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":[],"created_at":"2024-08-01T02:01:09.048Z","updated_at":"2025-10-21T18:46:57.074Z","avatar_url":"https://github.com/parroty.png","language":"Elixir","funding_links":[],"categories":["Third Party APIs"],"sub_categories":[],"readme":"# ExTwitter\n\n[![CI](https://github.com/parroty/extwitter/actions/workflows/test_and_lint.yaml/badge.svg)](https://github.com/parroty/extwitter/actions/workflows/test_and_lint.yaml)\n[![Coverage Status](http://img.shields.io/coveralls/parroty/extwitter.svg)](https://coveralls.io/r/parroty/extwitter)\n[![Module Version](https://img.shields.io/hexpm/v/extwitter.svg)](https://hex.pm/packages/extwitter)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/extwitter/)\n[![Total Download](https://img.shields.io/hexpm/dt/extwitter.svg)](https://hex.pm/packages/extwitter)\n[![License](https://img.shields.io/hexpm/l/extwitter.svg)](https://github.com/parroty/extwitter/blob/master/LICENSE.md)\n[![Last Updated](https://img.shields.io/github/last-commit/parroty/extwitter.svg)](https://github.com/parroty/extwitter/commits/master)\n\nTwitter client library for Elixir. It uses [OAuther](https://github.com/lexmag/oauther) to call Twitter's REST API v1.1.\n\nIt only supports very limited set of functions yet. Refer to [lib/extwitter.ex](https://github.com/parroty/extwitter/blob/master/lib/extwitter.ex) and [test/extwitter_test.exs](https://github.com/parroty/extwitter/blob/master/test/extwitter_test.exs) for available functions and examples.\n\n## Installation\n\nThe package can be installed by adding `:extwitter` to your list of\ndependencies in `mix.exs`:\n\nBy default, ExTwitter uses [OAuther](https://github.com/lexmag/oauther) and\n[Jason](https://github.com/michalmuskala/jason) library to call Twitter's REST\nAPI.\n\n```elixir\ndefp deps do\n  [\n    {:oauther, \"~\u003e 1.1\"},\n    {:jason, \"~\u003e 1.1\"},\n    {:extwitter, \"~\u003e 0.12\"}\n  ]\nend\n```\n\n## Configuration\n\nRefer to [Twitter API doc](https://dev.twitter.com/docs) for the detail.\n\nThe default behaviour is to configure using the application environment:\n\nIn `config/config.exs`, add:\n\n```elixir\nconfig :extwitter, :oauth, [\n   consumer_key: \"\",\n   consumer_secret: \"\",\n   access_token: \"\",\n   access_token_secret: \"\"\n]\n```\n\nOr manually at runtime through `ExTwitter.configure/1`:\n\n```elixir\niex\u003e ExTwitter.configure([consumer_key: \"\", ...])\n```\n\nYou can also configure the current process only:\n\n```elixir\niex\u003e ExTwitter.configure(:process, [consumer_key: \"\", ...])\n```\n\nYou can also customize it to use another library via the `:json_library`\nconfiguration:\n\n```elixir\nconfig :extwitter, :json_library, Poison\n```\n\nProxy for accessing twitter server can be configured as follows:\n\n```elixir\nconfig :extwitter, :proxy, [\n   server: \"www-proxy.mycompany.com\",\n   port: 8000,\n   user: \"user\",\n   password: \"password\"\n]\n```\n\n## Usage\n\nSample execution on IEx.\n\n### Setup and configuration\n\n```elixir\n$ iex -S mix\nInteractive Elixir - press Ctrl+C to exit (type h() ENTER for help)\n```\n\n```elixir\nExTwitter.configure(\n   consumer_key: System.get_env(\"TWITTER_CONSUMER_KEY\"),\n   consumer_secret: System.get_env(\"TWITTER_CONSUMER_SECRET\"),\n   access_token: System.get_env(\"TWITTER_ACCESS_TOKEN\"),\n   access_token_secret: System.get_env(\"TWITTER_ACCESS_SECRET\")\n )\n```\n\n### Authentication / Authorization\n\nExample for authentication ([Sign-in with twitter](https://dev.twitter.com/web/sign-in/implementing)).\n\nAuthorization ([3-legged authorization](https://dev.twitter.com/oauth/3-legged)) uses the same workflow, just swap `:authenticate_url` for `:authorize_url` where indicated.\n\n```elixir\n# Request twitter for a new token\ntoken = ExTwitter.request_token(\"http://myapp.com/twitter-callback\")\n\n# Generate the url for \"Sign-in with twitter\".\n# For \"3-legged authorization\" use ExTwitter.authorize_url instead\n{:ok, authenticate_url} = ExTwitter.authenticate_url(token.oauth_token)\n\n# Copy the url, paste it in your browser and authenticate\nIO.puts authenticate_url\n```\n\nAfter sign-in you will be redirected to the callback URL you configured for\nyour app. Get the tokens from the URL's query:\n\n```\nhttps://myapp.com/twitter-callback?oauth_token=\u003cTOKEN\u003e\u0026oauth_verifier=\u003cVERIFIER\u003e\n```\n\nCopy the `oauth_token` and `oauth_verifier` query strings from the URL and use\nit in the IEx snippet below.\n\n```elixir\noauth_token = \"\u003cTOKEN\u003e\"\noauth_verifier = \"\u003cVERIFIER\u003e\"\n\n# Exchange for an access token\n{:ok, access_token} = ExTwitter.access_token(oauth_verifier, oauth_token)\n\n# Configure ExTwitter to use your newly obtained access token\nExTwitter.configure(\n  consumer_key: System.get_env(\"TWITTER_CONSUMER_KEY\"),\n  consumer_secret: System.get_env(\"TWITTER_CONSUMER_SECRET\"),\n  access_token: access_token.oauth_token,\n  access_token_secret: access_token.oauth_token_secret\n)\n\nExTwitter.user_timeline\n```\n\n### Searching\n\nExample for normal API.\n\n```elixir\niex\u003e ExTwitter.search(\"elixir-lang\", [count: 5]) |\u003e\n     Enum.map(fn(tweet) -\u003e tweet.text end) |\u003e\n     Enum.join(\"\\n-----\\n\") |\u003e\n     IO.puts\n\n# =\u003e Tweets will be displayed in the console as follows.\n@xxxx have you tried this yet?\n-----\n@yyyy You mean this? http://t.co/xxxx That had sailed below my radar thus far.\n-----\n@zzzz #elixir-lang. I'm jadams\n-----\nAkala ko 100 nalang kulang ko sa dark elixir para sa Barb King summoner level.\n-----\n@aaaa usually kasi magbbuzz lang yan pag luma na string. talaga ang elixir.\n```\n\n### Streaming\n\nExample for streaming API.\n\n```elixir\nstream = ExTwitter.stream_filter(track: \"apple\") |\u003e\nStream.map(fn(x) -\u003e x.text end) |\u003e\nStream.map(fn(x) -\u003e IO.puts \"#{x}\\n---------------\\n\" end)\n\nEnum.to_list(stream)\n\n# =\u003e Tweets will be displayed in the console as follows.\nApple 'iWatch' rumour round-up\n---------------\nApple iPhone 4s 16GB Black Verizon - Cracked Screen, WORKS PERFECTLY!\n---------------\nApple iPod nano 7th Generation (PRODUCT) RED (16 GB) (Latest Model) - Full read by\n---------------\n...\n```\n\nThe `ExTwitter.stream_control/2` function to send a message to stop the stream.\n\n```elixir\n# An example to stop receiving stream after 5 seconds passed.\npid = spawn(fn -\u003e\n  stream = ExTwitter.stream_filter(track: \"apple\")\n  for tweet \u003c- stream do\n    IO.puts tweet.text\n  end\nend)\n\n:timer.sleep(5000)\nExTwitter.stream_control(pid, :stop)\n```\n\nTwitter returns several [streaming message types](https://dev.twitter.com/streaming/overview/messages-types\"). These messages are returned when `:receive_messages` option is specified.\n\n```elixir\nstream = ExTwitter.stream_sample(receive_messages: true)\n\nfor message \u003c- stream do\n  case message do\n    tweet = %ExTwitter.Model.Tweet{} -\u003e\n      IO.puts \"tweet = #{tweet.text}\"\n\n    deleted_tweet = %ExTwitter.Model.DeletedTweet{} -\u003e\n      IO.puts \"deleted tweet = #{deleted_tweet.status[:id]}\"\n\n    limit = %ExTwitter.Model.Limit{} -\u003e\n      IO.puts \"limit = #{limit.track}\"\n\n    stall_warning = %ExTwitter.Model.StallWarning{} -\u003e\n      IO.puts \"stall warning = #{stall_warning.code}\"\n\n    _ -\u003e\n      IO.inspect message\n  end\nend\n```\n\n### Cursor\n\nSome of Twitter API have paging capability for retrieving large number of items\nthrough cursor. The following is an example to iteratively call the API to\nfetch all the items.\n\n```elixir\ndefmodule Retriever do\n  def follower_ids(screen_name, acc \\\\ [], cursor \\\\ -1) do\n    cursor = fetch_next(screen_name, cursor)\n    if Enum.count(cursor.items) == 0 do\n      List.flatten(acc)\n    else\n      follower_ids(screen_name, [cursor.items|acc], cursor.next_cursor)\n    end\n  end\n\n  defp fetch_next(screen_name, cursor) do\n    try do\n      ExTwitter.follower_ids(screen_name, cursor: cursor)\n    rescue\n      e in ExTwitter.RateLimitExceededError -\u003e\n        :timer.sleep ((e.reset_in + 1) * 1000)\n        fetch_next(screen_name, cursor)\n    end\n  end\nend\n\nids = Retriever.follower_ids(\"TwitterDev\")\nIO.puts \"Follower count for TwitterDev is #{Enum.count(ids)}.\"\n# =\u003e Follower count for TwitterDev is 38469.\n```\n\n## Development\n\n`run_iex.sh` launches IEx, with initially calling `ExTwitter.configure/1` defined\nas `iex/dot.iex`.\n\n```elixir\n$ ./run_iex.sh\nErlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10]...\nInteractive Elixir (1.0.2) - press Ctrl+C to exit (type h() ENTER for help)\n\niex\u003e (ExTwitter.search(\"elixir\") |\u003e List.first).text\n```\n\n## Copyright and License\n\nCopyright (c) 2014 parroty\n\nThis work is free. You can redistribute it and/or modify it under the\nterms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparroty%2Fextwitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparroty%2Fextwitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparroty%2Fextwitter/lists"}