Published Tuesday 10th March 2015

Reading from a Twitter feed with PHP

This is an old post and Twitter's API is no longer freely accessible. We've kept it though, because it might still be useful to somebody.

It used to be pretty easy to output a Twitter feed onto your website, but since Twitter decided to close down their public feeds (both RSS and XML), and introduce OAuth into their API, doing this became a bit of a headache. This happened quite some time ago now but there still seems to be a large number of websites out there with broken Twitter outputs so here's a quick tutorial to get you up and running again.

For the record, I tend to recommend doing this server-side rather than using any of the available Javascript options, because this results in static HTML that Google etc can parse, making Twitter outputs a good way to keep your pages constantly updating which is great for SEO. Additionally, Javascript relies on client-side support which makes it a poor choice for anything other than fancying-up your website, assuming you care about accessibility.

  • First of all head over to and sign in with the same credentials that you use to access the Twitter account that you intend to output from.
  • Select Tools -> Manage Your Apps from the home page, then Create New App.
  • Type in a sensible name, like "Feed for my website", a description like "API access for my website" and the url of your website. This information won't actually be output anywhere or effect how the feed works but we need to provide it before we can get our authentication keys. If we were creating something that posted to Twitter or required more interaction with your account, these fields would be more relevant. Agree to the terms and submit.
  • You'll be taken to the details page of the 'app' you've just created. Under Application Settings hit the Manage Keys and Access Tokens link.
  • Note down the Consumer Key and Consumer Secret. We'll need to reference these within the website code later. Then hit the Create Access Token and again note down the generated Access Token and Access Token Secret. You now have everything needed to access your Twitter account through the API.
  • If you've been asked by your developer to generate these keys, pass all 4 over to them and you're done. Otherwise if you are a developer, copy the following code to your website and populate the variables at the top.
    $screen_name = 'Your Twitter Name';
    $count = 1; // How many tweets to output
    $retweets = 0; // 0 to exclude, 1 to include

    // Populate these with the keys/tokens you just obtained
    $oauthAccessToken = '';
    $oauthAccessTokenSecret = '';
    $oauthConsumerKey = '';
    $oauthConsumerSecret = '';

    // First we populate an array with the parameters needed by the API
    $oauth = array(
        'count' => $count,
        'include_rts' => $retweets,
        'oauth_consumer_key' => $oauthConsumerKey,
        'oauth_nonce' => time(),
        'oauth_signature_method' => 'HMAC-SHA1',
        'oauth_timestamp' => time(),
        'oauth_token' => $oauthAccessToken,
        'oauth_version' => '1.0'

    $arr = array();
    foreach($oauth as $key => $val)
        $arr[] = $key.'='.rawurlencode($val);

    // Then we create an encypted hash of these values to prove to the API that they weren't tampered with during transfer
    $oauth['oauth_signature'] = base64_encode(hash_hmac('sha1', 'GET&'.rawurlencode('').'&'.rawurlencode(implode('&', $arr)), rawurlencode($oauthConsumerSecret).'&'.rawurlencode($oauthAccessTokenSecret), true));

    $arr = array();
    foreach($oauth as $key => $val)
        $arr[] = $key.'="'.rawurlencode($val).'"';

    // Next we use Curl to access the API, passing our parameters and the security hash within the call
    $tweets = curl_init();
    curl_setopt_array($tweets, array(
        CURLOPT_HTTPHEADER => array('Authorization: OAuth '.implode(', ', $arr), 'Expect:'),
        CURLOPT_HEADER => false,
        CURLOPT_URL => ''.$count.'&include_rts='.$retweets,
        CURLOPT_SSL_VERIFYPEER => false,

    $json = curl_exec($tweets);

    // $json now contains the response from the Twitter API, which should include however many tweets we asked for.

    // Loop through them for output
    foreach(json_decode($json) as $status) {
        // Convert links back into actual links, otherwise they're just output as text
        $enhancedStatus = htmlentities($status->text, ENT_QUOTES, 'UTF-8');
        $enhancedStatus = preg_replace('/http:\/\/\/([a-zA-Z0-9]+)/i', '<a href="$1">http://$1</a>', $enhancedStatus);
        $enhancedStatus = preg_replace('/https:\/\/\/([a-zA-Z0-9]+)/i', '<a href="$1">http://$1</a>', $enhancedStatus);

        // Finally, output a simple paragraph containing the tweet and a link back to the Twitter account itself. You can format/style this as you like.
<p>&quot;<?php echo $enhancedStatus; ?>&quot;<br /><a href="<?php echo $screen_name; ?>">@<?php echo $screen_name; ?></a></p>

If you want the link back to open in a classic Twitter pop-up, add this Javascript to your page too:

<script type="text/javascript" src="//"></script>
Photo of Ric


Ric is a senior web and game programmer with nearly 30 years industry experience and countless programming languages in his skillset. He's worked for and with a number of design and development agencies, and is the proprietor of QWeb Ltd. Ric is also a Linux server technician and an advocate of free, open-source technologies. He can be found on Mastodon where he often posts about the projects he's working on both for and outside of QWeb Ltd, or you can follow and support his indie game project on Kofi. Ric also maintains our Github page of useful scripts.

Blog posts are written by individuals and do not necessarily depict the opinions or beliefs of QWeb Ltd or its current employees. Any information provided here might be biased or subjective, and might become out of date.

Discuss this post

Avatar for H20`

Jane, Tuesday 22nd December 2015 12:50

Thank you, I looked everywhere for such a simple solution.

Avatar for I0pvl\52p\v0

Intoxication, Tuesday 5th July 2016 12:00

Thank you for such a simple solution.
Please is it possible to have the twitter profile image displayed as well?

Avatar for C\5

Ric, Tuesday 5th July 2016 12:44

Profile images are available via another API endpoint,

If you therefore replace the two url instances in the above code with the new endpoint, strip out the count and include_rts values from the $oauth array, and add in the required screen_name value to the end of that array and as a parameter to the CURLOPT_URL value, the new response should include a profile_image_url part.

More information here:

And a working example here:

Avatar for I0pvl\52p\v0

Intoxication, Tuesday 5th July 2016 14:53

Worked perfectly.

Thank you so much. You are a legend.

Avatar for C\5

Ric, Tuesday 5th July 2016 15:01

No worries. If you need anything further do get in touch.

Avatar for n\[2k

vijay, Monday 26th September 2016 07:22

how to execute this program

Avatar for C\5

Ric, Monday 26th September 2016 10:01

This should work on any Curl enabled PHP server, Vijay.

Avatar for n2Y`y\v

valerio, Thursday 11th May 2017 14:17 doesn’t have a login. i think the right place is

Avatar for n2Y`y\v

valerio, Thursday 11th May 2017 14:25

is there a way to use this php code in a simple html page? what would you suggest?

Avatar for C\5

Ric, Thursday 11th May 2017 14:52 actually still works, but you’ve to sign in to the regular Twitter front before heading there. You should then see links to create/manage the apps associated to that account. You’re right though, is the same place.

If you’re running an nginx + Apache set-up, chances are your .html pages are being served by nginx without any PHP parsing, and for performance it’s a good idea to keep it that way. In which case you won’t be able to include PHP code directly on those pages I’m afraid. You could however add a Javscript to call a PHP script on page load, which could in turn respond with the HTML to output. jQuery.get() would be my approach for that.

Avatar for B\y\z]2 K2y2u2p\

Sirisha Garapati, Wednesday 14th June 2017 09:20

Thank you for the article.

Avatar for H2zv0

Jason, Thursday 3rd August 2017 09:08

Great article, thank you. Is there a way to get the expanded url to display under the tweet please?
Thanks in advance

Avatar for C\5

Ric, Thursday 3rd August 2017 10:43

You’ll find an array of urls within the entities object for that, one for each of the shorturls used in the post.

For example if you posts includes the shorturl then in the returned json data you should see something like this:

$status->entities->urls[0]->url => ‘’
$status->entities->urls[0]->expanded_url => ‘’

If your post includes 2 urls then you’d see this:

$status->entities->urls[0]->url => ‘’
$status->entities->urls[0]->expanded_url => ‘’
$status->entities->urls[1]->url => ‘’
$status->entities->urls[1]->expanded_url => ‘’

And so on.

Avatar for H2zv0

Jason, Thursday 3rd August 2017 11:18

Fantastic, thank you so much for your help.


Avatar for My\Z

Erik, Monday 7th August 2017 21:55

Very useful script. It just works. Thank you!
Two questions though:
1) how to filter for #hashtags? (yes, it is possible to filter *after* you have received the tweets, but I’m assuming Twitter has an API for that)
2) how to obtain tweet metadata like creation time and coordinates using your script as a starting point?

Thanks in advance!


Avatar for C\5

Ric, Monday 7th August 2017 23:08

Twitter has a search endpoint which I believe works exclusively on hashtags, though I could be wrong about that.

Regarding metadata, if you just replace lines 51 – 59 of the above script with a print_r($status); you’ll see the available metadata from the user_timeline endpoint that this script uses.

Avatar for P2]y2X

Bahram, Saturday 2nd December 2017 19:06

Very useful, thank you so much.

Avatar for [2p\0a`y

jatinder, Monday 4th December 2017 14:24

It worked fine, but i need to get tweet posted date. how i get posted date in yours this code…

Avatar for C\5

Ric, Monday 4th December 2017 14:55

In the example above, $status->created_at should contain a value for that which you can pass through strtotime() to convert to a Unix timestamp.

Avatar for I02k2p O2zz2X42\

Inayat Cassambai, Tuesday 17th July 2018 16:51


The script works a charm, but i have one query.

How do i pull in the media data for each tweet? So if i have an image i can output that as well.

Thank you.

Avatar for C\5

Ric, Tuesday 17th July 2018 17:19

If images are available within a tweet, you should see a $status->entities->media array that contains those. It expect it’s the media_url value that you’d want from that, to then just render as an img src.

Avatar for I02k2p O2zz2X42\

Inayat Cassambai, Wednesday 18th July 2018 09:12

Thanks for the reply Ric.

Just been looking through the docs, and the API we’re querying doesn’t seem to have any parameters for media entities unfortunately.

Tis a shame as i feel like that should be necessary to have. Unless i’m missing something.

Although what’s interesting is, one of my colleagues has successfully pulled in images from their tweets by passing the tweet_mode=extended parameter.$username&count=$count&include_rts=$retweet

Even though that’s not mentioned in the parameters list in the docs, that seems to have worked for him. I’ve tried adding that to your snippet but it didn’t work, probably because i’m not adding something to your authentication array too.

Avatar for C\5

Ric, Wednesday 18th July 2018 09:32

That’s strange. We’ve definitely integrated Twitter inclusive of posted media somewhere and the code would have been somewhat similar to the above, but for the life of me I can’t think where we did that now.

Twitter do keep changing their API so it’s entirely possible that the parameter you’ve found is how you were supposed to do this originally and they’ve since separated the endpoints out but left that param in for compatibility with old scripts. I’d be tempted to just go with that approach for the time being, but yes you would need to add to the oAuth array too, in the same order that you’ve added it to the actual call, just like the count and include_rts params are included.

Avatar for Fo\z

Luis, Saturday 5th December 2020 12:56

Im trying to modify this code to send a simple text tweet. Tríed but Im stuck :(

Avatar for C\5

Ric, Sunday 6th December 2020 16:31

Hi Luis. You'll need to submit to update.json instead of user_timeline.json but the process should be fairly similar:

Avatar for >\YY\2Xrvm

WilliamNow, Tuesday 26th October 2021 23:23

Good article! We will be linking to this particularly great article on our site. Keep up the good writing.

Avatar for F`vp2s0`y4

LeotaOnerb, Sunday 6th August 2023 09:54

Do you mind if I quote a couple of your posts as long as I provide credit and sources back to your weblog? My blog is in the very same area of interest as yours and my users would definitely benefit from some of the information you present here. Please let me know if this ok with you. Thanks a lot!

Avatar for C\5

Ric, Sunday 6th August 2023 10:39

You're welcome to quote, with citation, any of our content.

Leave a comment

Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text. You won't be added to any mailing list, and your details won't be shared with any third party.

This site is protected by reCAPTCHA and the Google Privacy Policy & Terms of Service apply.