what is the difference between data and params in requests?

Params are sent in (appended to) the URI (http://www.answer.com/here?param1=1&param2=2) while data is sent in the request body. Usually sensitive data or that sent in large volumes is posted in the body because it's easier to secure and doesn't lead to huge URIs.


First of all, there are two different methods:

  • requests.post() makes a POST request (placing all the parameters in the body)
  • requests.get() makes a GET request (placing all the parameters in the URL)

Then, according to the docs, you can choose between two parameters to send all the key/value data:

  • params=, without string modifications.
  • data=, applying a form-encoding string modification to the parameters.

So, you have 4 choices to send your request:

  • requests.post(url, params=)
  • requests.post(url, data=)
  • requests.get(url, params=)
  • requests.get(url, data=)

I don't think the currently accepted answer is correct. He is actually talking about requests.post() but using requests.get() in his own example.


According to the requests documentation:

  • A requests.post(url, data=data) will make an HTTP POST request, and
  • A requests.get(url, params=params) will make an HTTP GET request

To understand the difference between the two, see this answer.

Here's how params can be used in a GET:

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.text)

Which outputs

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  [...]
  "url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice that the payload ended up in the query string of the URL. Since they ended up there, they are viewable by anyone who has access to the URL, which is why you shouldn't use query strings for sensitive data like passwords.

Here's how data can be used in a POST:

payload = 'foobar'
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)

Which outputs

{
  "args": {}, 
  "data": "foobar", 
  [...]
  "url": "http://httpbin.org/post"
}

Notice how the POST data does not show up in the query strings, as they are transmitted through the body of the request instead.


Critique of this answer has pointed out that there are more options. I never denied such a thing in my original answer, but let's take a closer look.

The documentation examples always show:

  • The params keyword used for GET, and
  • The data keyword used for POST

But that doesn't mean they are mutually exclusive.

In theory you could mix the two together in a POST:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', params=params, data=data)
print(r.text)

Which outputs

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  "data": "foobar", 
  [...]
  "url": "http://httpbin.org/post?key1=value1&key2=value2"
}

But you cannot mix data into a GET:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=params, data=data)
print(r.text)

Outputs:

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  [...]
  "url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice how the data field is gone.